diff options
Diffstat (limited to 'eidas_modules/authmodule-eIDAS-v2/src')
8 files changed, 323 insertions, 143 deletions
| diff --git a/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/Constants.java b/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/Constants.java index 6da30299..40bcd27a 100644 --- a/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/Constants.java +++ b/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/Constants.java @@ -314,10 +314,12 @@ public class Constants {    // UI options    public static final String HTML_FORM_ADVANCED_MATCHING_FAILED = "advancedMatchingFailed"; - +      // ProcessEngine context    public static final String CONTEXT_FLAG_ADVANCED_MATCHING_FAILED = HTML_FORM_ADVANCED_MATCHING_FAILED; +  public static final String CONTEXT_FLAG_ADVANCED_MATCHING_FAILED_REASON =  +      HTML_FORM_ADVANCED_MATCHING_FAILED + "Reason";    /**     * {@link at.asitplus.eidas.specific.modules.auth.eidas.v2.tasks.CreateNewErnpEntryTask}. diff --git a/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/clients/zmr/IZmrClient.java b/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/clients/zmr/IZmrClient.java index c4e8ece0..f3c32c96 100644 --- a/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/clients/zmr/IZmrClient.java +++ b/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/clients/zmr/IZmrClient.java @@ -29,6 +29,7 @@ import javax.annotation.Nonnull;  import javax.annotation.Nullable;  import at.asitplus.eidas.specific.modules.auth.eidas.v2.clients.zmr.ZmrSoapClient.ZmrRegisterResult; +import at.asitplus.eidas.specific.modules.auth.eidas.v2.controller.AdresssucheController.AdresssucheOutput;  import at.asitplus.eidas.specific.modules.auth.eidas.v2.dao.RegisterResult;  import at.asitplus.eidas.specific.modules.auth.eidas.v2.dao.SimpleEidasData;  import at.asitplus.eidas.specific.modules.auth.eidas.v2.exception.EidasSAuthenticationException; @@ -80,6 +81,23 @@ public interface IZmrClient {            throws EidasSAuthenticationException;    /** +   * Search person based on MDS information and Austrian residence. +   *  +   * @param zmrProzessId zmrProzessId zmrProzessId ProcessId from ZMR or <code>null</code> if no processId exists +   * @param givenName eIDAS given name +   * @param familyName eIDAS principle name +   * @param dateOfBirth eIDAS date-of-birth +   * @param citizenCountryCode citizenCountryCode CountryCode of the eIDAS proxy-service +   * @param address Address information for searching +   * @return Search result but never <code>null</code> +   * @throws EidasSAuthenticationException In case of a communication error  +   */ +  @Nonnull +  ZmrRegisterResult searchWithResidenceData(@Nullable BigInteger zmrProzessId, @Nonnull String givenName,  +      @Nonnull String familyName, @Nonnull String dateOfBirth, @Nonnull String citizenCountryCode,  +      @Nonnull AdresssucheOutput address) throws EidasSAuthenticationException; +   +  /**     * Update ZMR entry to KITT existing ZMR identity with this eIDAS authentication.     *      * @param zmrProzessId zmrProzessId ProcessId from ZMR or <code>null</code> if no processId exists @@ -92,7 +110,4 @@ public interface IZmrClient {    ZmrRegisterResult update(@Nullable BigInteger zmrProzessId, RegisterResult registerResult, SimpleEidasData eidData)        throws EidasSAuthenticationException; -  ZmrRegisterResult searchWithResidenceData(@Nullable BigInteger zmrProzessId, String givenName, String familyName,  -      String dateOfBirth, String zipcode, String city, String street); -  } diff --git a/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/clients/zmr/ZmrSoapClient.java b/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/clients/zmr/ZmrSoapClient.java index 18a80c33..0f2f94cc 100644 --- a/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/clients/zmr/ZmrSoapClient.java +++ b/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/clients/zmr/ZmrSoapClient.java @@ -24,6 +24,7 @@ import org.springframework.lang.Nullable;  import at.asitplus.eidas.specific.modules.auth.eidas.v2.Constants;  import at.asitplus.eidas.specific.modules.auth.eidas.v2.clients.AbstractSoapClient; +import at.asitplus.eidas.specific.modules.auth.eidas.v2.controller.AdresssucheController.AdresssucheOutput;  import at.asitplus.eidas.specific.modules.auth.eidas.v2.dao.RegisterResult;  import at.asitplus.eidas.specific.modules.auth.eidas.v2.dao.SimpleEidasData;  import at.asitplus.eidas.specific.modules.auth.eidas.v2.exception.EidasSAuthenticationException; @@ -56,6 +57,8 @@ import at.gv.bmi.namespace.zmr_su.zmr._20040201.SuchkriterienType;  import at.gv.e_government.reference.namespace.persondata.de._20040201.IdentificationType;  import at.gv.e_government.reference.namespace.persondata.de._20040201.NatuerlichePersonTyp;  import at.gv.e_government.reference.namespace.persondata.de._20040201.PersonenNameTyp; +import at.gv.e_government.reference.namespace.persondata.de._20040201.PostAdresseTyp; +import at.gv.e_government.reference.namespace.persondata.de._20040201.ZustelladresseTyp;  import at.gv.egiz.eaaf.core.api.data.EaafConstants;  import at.gv.egiz.eaaf.core.exceptions.EaafAuthenticationException;  import at.gv.egiz.eaaf.core.exceptions.EaafConfigurationException; @@ -95,6 +98,7 @@ public class ZmrSoapClient extends AbstractSoapClient implements IZmrClient {        "Searching " + Constants.eIDAS_ATTR_PERSONALIDENTIFIER;    private static final String PROCESS_SEARCH_MDS_ONLY = "Searching with MDS only";    private static final String PROCESS_SEARCH_COUNTRY_SPECIFIC = "Searching {0} specific"; +  private static final String PROCESS_SEARCH_BY_RESIDENCE = "Searching by residence";    private static final String PROCESS_KITT_GENERAL = "KITT general-processing";    private static final String PROCESS_KITT_IDENITIES_GET = "KITT get-latest-version"; @@ -173,15 +177,7 @@ public class ZmrSoapClient extends AbstractSoapClient implements IZmrClient {        // set eIDAS person information        final PersonSuchenRequest searchPersonReq = new PersonSuchenRequest();        req.setPersonSuchenRequest(searchPersonReq); - -      final NatuerlichePersonTyp searchNatPerson = new NatuerlichePersonTyp(); -      searchPersonReq.setNatuerlichePerson(searchNatPerson); -      final PersonenNameTyp searchNatPersonName = new PersonenNameTyp(); -      searchNatPerson.setPersonenName(searchNatPersonName); - -      searchNatPersonName.setFamilienname(familyName); -      searchNatPersonName.setVorname(givenName); -      searchNatPerson.setGeburtsdatum(dateOfBirth); +      searchPersonReq.setNatuerlichePerson(buildSearchNatPerson(givenName, familyName, dateOfBirth));        // set work-flow client information        req.setWorkflowInfoClient(generateWorkFlowInfos(PROCESS_TASK_SEARCH, zmrProzessId)); @@ -296,12 +292,49 @@ public class ZmrSoapClient extends AbstractSoapClient implements IZmrClient {      }    } -   +        @Override    public ZmrRegisterResult searchWithResidenceData(BigInteger zmrProzessId, String givenName, String familyName,  -      String dateOfBirth, String zipcode, String city, String street) { -    // TODO Auto-generated method stub -    return null; +      String dateOfBirth, String citizenCountryCode, AdresssucheOutput address) +          throws EidasSAuthenticationException { +    try { +      // build search request +      final RequestType req = new RequestType(); + +      // set person information +      final PersonSuchenRequest searchPersonReq = new PersonSuchenRequest(); +      req.setPersonSuchenRequest(searchPersonReq); +      searchPersonReq.setNatuerlichePerson(buildSearchNatPerson(givenName, familyName, dateOfBirth));        +      searchPersonReq.setPostAdresse(buildSearchAddress(address)); + +      // set work-flow client information +      req.setWorkflowInfoClient(generateWorkFlowInfos(PROCESS_SEARCH_BY_RESIDENCE, zmrProzessId)); +      req.setClientInfo(generateClientInfos()); + +      // set additionl search parameters +      searchPersonReq.setPersonensucheInfo(generateSearchCriteria( +          PROCESS_SEARCH_BY_RESIDENCE, false, true, false)); + +      // request ZMR +      log.trace("Requesting ZMR for '{}' operation", PROCESS_SEARCH_BY_RESIDENCE); +      final ResponseType resp = zmrClient.service(req, null); + +      // parse ZMR response +      return processZmrResponse(resp, citizenCountryCode, false, PROCESS_SEARCH_BY_RESIDENCE); + +    } catch (final ServiceFault e) { +      final String errorMsg = extractReasonFromError(e); +      log.warn(LOGMSG_ZMR_ERROR, PROCESS_SEARCH_BY_RESIDENCE, errorMsg); +      throw new ZmrCommunicationException(ERROR_MATCHING_01, new Object[] { errorMsg }, e); + +    } catch (EidasSAuthenticationException e) { +      throw e; +       +    } catch (final Exception e) { +      log.warn(LOGMSG_ZMR_RESP_PROCESS, PROCESS_SEARCH_BY_RESIDENCE, e.getMessage()); +      throw new EidasSAuthenticationException(ERROR_MATCHING_99, new Object[] { e.getMessage() }, e); + +    }    }    @PostConstruct @@ -685,6 +718,43 @@ public class ZmrSoapClient extends AbstractSoapClient implements IZmrClient {      }    } +  private NatuerlichePersonTyp buildSearchNatPerson(String givenName, String familyName, String dateOfBirth) { +    final NatuerlichePersonTyp searchNatPerson = new NatuerlichePersonTyp();     +    final PersonenNameTyp searchNatPersonName = new PersonenNameTyp(); +    searchNatPerson.setPersonenName(searchNatPersonName); +    searchNatPersonName.setFamilienname(familyName); +    searchNatPersonName.setVorname(givenName); +    searchNatPerson.setGeburtsdatum(dateOfBirth); +    return searchNatPerson; +     +  } +   +  private PostAdresseTyp buildSearchAddress(AdresssucheOutput address) { +    PostAdresseTyp postAdresse = new PostAdresseTyp(); +    if (StringUtils.isNotBlank(address.getPostleitzahl())){ +      postAdresse.setPostleitzahl(address.getPostleitzahl()); +    } +    if (StringUtils.isNotBlank(address.getMunicipality())) { +      postAdresse.setGemeinde(address.getMunicipality()); +    } +    if (StringUtils.isNotBlank(address.getVillage())) { +      postAdresse.setOrtschaft(address.getVillage()); +    } +    if (StringUtils.isNotBlank(address.getStreet()) || StringUtils.isNotBlank(address.getNumber())) { +      ZustelladresseTyp zustelladresse = new ZustelladresseTyp(); +      if (StringUtils.isNotBlank(address.getStreet())) { +        zustelladresse.setStrassenname(address.getStreet()); +      } +      if (StringUtils.isNotBlank(address.getNumber())) { +        zustelladresse.setOrientierungsnummer(address.getNumber()); +      } +      postAdresse.setZustelladresse(zustelladresse); +    } +     +    return postAdresse; +     +  } +      private Collection<? extends EidasIdentitaetAnlageType> selectEidasDocumentsToAdd(        PersonErgebnisType zmrPersonToKitt, SimpleEidasData eidData) { diff --git a/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/controller/AdresssucheController.java b/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/controller/AdresssucheController.java index 8505f5d5..6dcd4879 100644 --- a/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/controller/AdresssucheController.java +++ b/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/controller/AdresssucheController.java @@ -58,6 +58,7 @@ import at.gv.egiz.eaaf.core.exceptions.EaafException;  import at.gv.egiz.eaaf.core.exceptions.GuiBuildException;  import at.gv.egiz.eaaf.core.exceptions.PendingReqIdValidationException;  import lombok.AllArgsConstructor; +import lombok.Builder;  import lombok.Data;  import lombok.extern.slf4j.Slf4j; @@ -166,18 +167,23 @@ public class AdresssucheController {          number.replaceAll("[\r\n]", ""));          try {        pendingReqGeneration.validateAndGetPendingRequestId(pendingId); +            } catch (PendingReqIdValidationException e) {        log.warn("Search with pendingId '{}' is not valid", pendingId.replaceAll("[\r\n]", ""));        return ResponseEntity.badRequest().build(); +            } +          try {        Adressdaten searchInput = buildSearchInput(postleitzahl, municipality, village, street, number);        ZmrAddressSoapClient.AddressInfo searchOutput = client.searchAddress(searchInput);        AdresssucheResult output = buildResponse(searchOutput);        return ResponseEntity.ok(output); +            } catch (EidasSAuthenticationException e) {        log.warn("Search failed", e);        return ResponseEntity.badRequest().build(); +            }    } @@ -185,7 +191,9 @@ public class AdresssucheController {      if (searchOutput.getPersonResult().isEmpty()) {        log.warn("No result from ZMR");        return new AdresssucheResult(Collections.emptyList(), 0); +            } +          log.info("Result level is {}", searchOutput.getLevel());      Set<AdresssucheOutput> result = searchOutput.getPersonResult().stream()          .map(Adressdaten::getPostAdresse) @@ -195,6 +203,7 @@ public class AdresssucheController {      // TODO Add configuration option for the limit of 30      List<AdresssucheOutput> sorted = result.stream().sorted().limit(30).collect(Collectors.toList());      return new AdresssucheResult(sorted, result.size()); +        }    private Adressdaten buildSearchInput(String postleitzahl, @@ -225,6 +234,7 @@ public class AdresssucheController {      Adressdaten searchInput = new Adressdaten();      searchInput.setPostAdresse(postAdresse);      return searchInput; +        }    @Data @@ -236,6 +246,7 @@ public class AdresssucheController {    @Data    @AllArgsConstructor +  @Builder    public static class AdresssucheOutput implements Comparable<AdresssucheOutput> {      private final String postleitzahl;      private final String municipality; diff --git a/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/service/RegisterSearchService.java b/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/service/RegisterSearchService.java index 85ea942c..d95aadda 100644 --- a/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/service/RegisterSearchService.java +++ b/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/service/RegisterSearchService.java @@ -16,6 +16,7 @@ import at.asitplus.eidas.specific.modules.auth.eidas.v2.clients.ernp.ErnpRestCli  import at.asitplus.eidas.specific.modules.auth.eidas.v2.clients.ernp.IErnpClient;  import at.asitplus.eidas.specific.modules.auth.eidas.v2.clients.zmr.IZmrClient;  import at.asitplus.eidas.specific.modules.auth.eidas.v2.clients.zmr.ZmrSoapClient.ZmrRegisterResult; +import at.asitplus.eidas.specific.modules.auth.eidas.v2.controller.AdresssucheController.AdresssucheOutput;  import at.asitplus.eidas.specific.modules.auth.eidas.v2.dao.RegisterResult;  import at.asitplus.eidas.specific.modules.auth.eidas.v2.dao.SimpleEidasData;  import at.asitplus.eidas.specific.modules.auth.eidas.v2.exception.EidasSAuthenticationException; @@ -165,18 +166,27 @@ public class RegisterSearchService {     * Search with residence infos.     *     * @param operationStatus Current register-operation status that contains processing informations -   * @param zipcode         Provided Zipcode -   * @param city            Provided City -   * @param street          Provided street +   * @param eidasData Receive eIDAS eID information +   * @param address Address information provided by user     * @return Results from ZMR or ERnP search +   * @throws WorkflowException In case of a register interaction error     */ -  public RegisterStatusResults searchWithResidence(RegisterOperationStatus operationStatus, SimpleEidasData eidasData, -                                                   String zipcode, String city, String street) { -    final ZmrRegisterResult resultsZmr = zmrClient.searchWithResidenceData( -        operationStatus.getZmrProcessId(), eidasData.getGivenName(), eidasData.getFamilyName(), -        eidasData.getDateOfBirth(), zipcode, city, street); -    return RegisterStatusResults.fromZmr(resultsZmr); +  public RegisterStatusResults searchWithResidence(RegisterOperationStatus operationStatus, SimpleEidasData eidasData,  +      AdresssucheOutput address) throws WorkflowException {     +    try { +      final ZmrRegisterResult resultsZmr = zmrClient.searchWithResidenceData(     +          operationStatus.getZmrProcessId(), eidasData.getGivenName(), eidasData.getFamilyName(), +          eidasData.getDateOfBirth(), eidasData.getCitizenCountryCode(), address); + +      // ERnP search is not used here, because we only search for people with Austrian residence and they are in ZMR only   +     +      return RegisterStatusResults.fromZmr(resultsZmr); +       +    } catch (final EidasSAuthenticationException e) { +      throw new WorkflowException("searchWithResidenceInformation", e.getMessage(), +          !(e instanceof ZmrCommunicationException), e); +    }    }    /** diff --git a/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/tasks/ReceiveAustrianResidenceGuiResponseTask.java b/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/tasks/ReceiveAustrianResidenceGuiResponseTask.java index acf469d3..67addf94 100644 --- a/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/tasks/ReceiveAustrianResidenceGuiResponseTask.java +++ b/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/tasks/ReceiveAustrianResidenceGuiResponseTask.java @@ -23,16 +23,24 @@  package at.asitplus.eidas.specific.modules.auth.eidas.v2.tasks; +import static at.asitplus.eidas.specific.modules.auth.eidas.v2.Constants.CONTEXT_FLAG_ADVANCED_MATCHING_FAILED; +import static at.asitplus.eidas.specific.modules.auth.eidas.v2.Constants.CONTEXT_FLAG_ADVANCED_MATCHING_FAILED_REASON; +import static at.asitplus.eidas.specific.modules.auth.eidas.v2.Constants.TRANSITION_TO_GENERATE_OTHER_LOGIN_METHOD_GUI_TASK; +  import java.util.Enumeration;  import javax.servlet.http.HttpServletRequest;  import javax.servlet.http.HttpServletResponse;  import org.apache.commons.lang.StringEscapeUtils; +import org.apache.commons.lang3.StringUtils;  import org.jetbrains.annotations.NotNull;  import org.springframework.stereotype.Component;  import at.asitplus.eidas.specific.modules.auth.eidas.v2.Constants; +import at.asitplus.eidas.specific.modules.auth.eidas.v2.controller.AdresssucheController; +import at.asitplus.eidas.specific.modules.auth.eidas.v2.controller.AdresssucheController.AdresssucheOutput; +import at.asitplus.eidas.specific.modules.auth.eidas.v2.controller.AdresssucheController.AdresssucheOutput.AdresssucheOutputBuilder;  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.ManualFixNecessaryException; @@ -43,15 +51,9 @@ import at.asitplus.eidas.specific.modules.auth.eidas.v2.utils.MatchingTaskUtils;  import at.gv.egiz.eaaf.core.api.idp.process.ExecutionContext;  import at.gv.egiz.eaaf.core.exceptions.EaafStorageException;  import at.gv.egiz.eaaf.core.exceptions.TaskExecutionException; -import at.gv.egiz.eaaf.core.impl.idp.auth.modules.AbstractAuthServletTask; -import lombok.AllArgsConstructor; -import lombok.Data; -import lombok.NoArgsConstructor; +import at.gv.egiz.eaaf.core.impl.idp.controller.tasks.AbstractLocaleAuthServletTask;  import lombok.extern.slf4j.Slf4j; -import static at.asitplus.eidas.specific.modules.auth.eidas.v2.Constants.CONTEXT_FLAG_ADVANCED_MATCHING_FAILED; -import static at.asitplus.eidas.specific.modules.auth.eidas.v2.Constants.TRANSITION_TO_GENERATE_OTHER_LOGIN_METHOD_GUI_TASK; -  /**   * Task receives the response of {@link GenerateAustrianResidenceGuiTask} and handles it. @@ -67,7 +69,7 @@ import static at.asitplus.eidas.specific.modules.auth.eidas.v2.Constants.TRANSIT   * </ul>   * Transitions:   * <ul> - *   <li>{@link CreateNewErnpEntryTask} if no results from search with residency data in registers</li> + *   <li>{@link GenerateOtherLoginMethodGuiTask} if no results from search with residency data in registers</li>   *   <li>{@link CreateIdentityLinkTask} if one exact match between initial register search (with MDS) and results   *   from search with residency data in registers exists</li>   *   <li>{@link GenerateOtherLoginMethodGuiTask} if a user input error has happened</li> @@ -79,71 +81,77 @@ import static at.asitplus.eidas.specific.modules.auth.eidas.v2.Constants.TRANSIT   */  @Slf4j  @Component("ReceiveAustrianResidenceGuiResponseTask") -public class ReceiveAustrianResidenceGuiResponseTask extends AbstractAuthServletTask { +public class ReceiveAustrianResidenceGuiResponseTask extends AbstractLocaleAuthServletTask { -  public static final String PARAM_FORMER_RESIDENCE_AVAILABLE = "formerResidenceAvailable"; -  public static final String PARAM_STREET = "street"; -  public static final String PARAM_CITY = "city"; -  public static final String PARAM_ZIPCODE = "zipcode"; +  private static final String MSG_PROP_20 = "module.eidasauth.matching.20"; +  private static final String MSG_PROP_21 = "module.eidasauth.matching.21"; +  private static final String MSG_PROP_22 = "module.eidasauth.matching.22"; +   +  public static final String HTTP_PARAM_NO_RESIDENCE = "noResidence";      private final RegisterSearchService registerSearchService;    public ReceiveAustrianResidenceGuiResponseTask(RegisterSearchService registerSearchService) {      this.registerSearchService = registerSearchService; +        } - -  @Data -  @AllArgsConstructor -  @NoArgsConstructor -  public static class UserInput { -    private boolean formerResidenceAvailable; -    private String zipcode; -    private String city; -    private String street; -  } - +      @Override -  public void execute(ExecutionContext executionContext, HttpServletRequest request, HttpServletResponse response) -      throws TaskExecutionException { +  protected void executeWithLocale(ExecutionContext executionContext, HttpServletRequest request, +      HttpServletResponse response) throws TaskExecutionException {      log.trace("Starting ReceiveAustrianResidenceGuiResponseTask"); -    UserInput input = parseHtmlInput(request); -    if (!input.isFormerResidenceAvailable()) { -      moveToNextTask(executionContext); -      return; - -    } - -    if (input.getStreet().isEmpty() || input.getCity().isEmpty() || input.getZipcode().isEmpty()) { -      // HTML form should ensure that mandatory fields are set => this should never happen -      executionContext.put(CONTEXT_FLAG_ADVANCED_MATCHING_FAILED, true); -      executionContext.put(TRANSITION_TO_GENERATE_OTHER_LOGIN_METHOD_GUI_TASK, true); -      return; - -    } +    try {     +      //return to AuswahlScreen if HTTP_PARAM_NO_RESIDENCE was selected +      final boolean forwardWithOutMandate = parseFlagFromHttpRequest(request, HTTP_PARAM_NO_RESIDENCE, false); +      if (forwardWithOutMandate) { +        log.debug("User selects 'no residence' button. Switch back to 'other matching' selection ... ");        +        executionContext.put(TRANSITION_TO_GENERATE_OTHER_LOGIN_METHOD_GUI_TASK, true); +       +        executionContext.put(CONTEXT_FLAG_ADVANCED_MATCHING_FAILED_REASON, MSG_PROP_20); +        executionContext.put(CONTEXT_FLAG_ADVANCED_MATCHING_FAILED, true);                   +        return; +       +      } +             +      //load search parameters from HTML form     +      AdresssucheOutput input = parseHtmlInput(request);         +      if (validateHtmlInput(input)) { +        // HTML form should ensure that mandatory fields are set => this should never happen +        log.warn("HTML form contains no residence information. Switch back to 'other matching' selection ... ");             +        executionContext.put(TRANSITION_TO_GENERATE_OTHER_LOGIN_METHOD_GUI_TASK, true); +       +        executionContext.put(CONTEXT_FLAG_ADVANCED_MATCHING_FAILED_REASON, MSG_PROP_20); +        executionContext.put(CONTEXT_FLAG_ADVANCED_MATCHING_FAILED, true);       +        return; -    try { +      } +     +      // get pre-processed information        SimpleEidasData eidasData = MatchingTaskUtils.getInitialEidasData(pendingReq);        RegisterStatusResults initialSearchResult = MatchingTaskUtils.getIntermediateMatchingResult(pendingReq); +      // search in register        RegisterStatusResults residencyResult = -          registerSearchService.searchWithResidence(initialSearchResult.getOperationStatus(), -              eidasData, input.zipcode, input.city, input.street); -      if (residencyResult.getResultCount() == 0) { -        //TODO: her we should add a GUI step of result is zero to inform user an forward process by click -        moveToNextTask(executionContext); - -      } else if (residencyResult.getResultCount() == 1) { -        compareSearchResultWithInitialData(executionContext, residencyResult, eidasData); +          registerSearchService.searchWithResidence(initialSearchResult.getOperationStatus(), eidasData, input); +       +      // validate matching response from registers +      if (residencyResult.getResultCount() != 1) { +        log.info("Find {} match by using residence information. Forward user to 'other matching' selection ... ", +            residencyResult.getResultCount() == 0 ? "no" : "more-than-one");        +        executionContext.put(TRANSITION_TO_GENERATE_OTHER_LOGIN_METHOD_GUI_TASK, true); +         +        executionContext.put(CONTEXT_FLAG_ADVANCED_MATCHING_FAILED_REASON, MSG_PROP_22); +        executionContext.put(CONTEXT_FLAG_ADVANCED_MATCHING_FAILED, true);            } else { -        /*TODO: align with form generation task and to better error handling in case of more-than-one result. -         *      Maybe the user has to provide more information. -         */ -        throw new TaskExecutionException(pendingReq, -            "Manual Fix necessary", new ManualFixNecessaryException(eidasData)); +        log.debug("Find single match by using residence information. Starting data validation ... "); +        compareSearchResultWithInitialData(executionContext, residencyResult, eidasData);        } +    } catch (WorkflowException e) { +      throw new TaskExecutionException(pendingReq, "Search with residency data failed", e); +            } catch (EaafStorageException e) {        log.error("Search with residency data failed", e);        throw new TaskExecutionException(pendingReq, "Search with residency data failed", e); @@ -151,58 +159,67 @@ public class ReceiveAustrianResidenceGuiResponseTask extends AbstractAuthServlet      }    } +  private boolean validateHtmlInput(AdresssucheOutput input) { +    return StringUtils.isEmpty(input.getMunicipality())  +        && StringUtils.isEmpty(input.getNumber()) +        && StringUtils.isEmpty(input.getPostleitzahl()) +        && StringUtils.isEmpty(input.getStreet()) +        && StringUtils.isEmpty(input.getVillage());             +  } +    private void compareSearchResultWithInitialData(ExecutionContext executionContext,        RegisterStatusResults residencyResult, SimpleEidasData eidasData)        throws TaskExecutionException, EaafStorageException {      try { -      if (eidasData.equalsRegisterData(residencyResult.getResult())) { +      if (!eidasData.equalsRegisterData(residencyResult.getResult())) {          // update register information -        registerSearchService.step7aKittProcess(residencyResult, eidasData); +        RegisterStatusResults updateResult = registerSearchService.step7aKittProcess(residencyResult, eidasData); -        // store search result to re-used in CreateIdentityLink step, because there we need bPK and MDS +        // store updated result to re-used in CreateIdentityLink step, because there we need bPK and MDS          MatchingTaskUtils.storeFinalMatchingResult(pendingReq,              MatchedPersonResult.generateFormMatchingResult( -                residencyResult.getResult(), eidasData.getCitizenCountryCode())); +                updateResult.getResult(), eidasData.getCitizenCountryCode()));        } else { -        moveToNextTask(executionContext); - +        log.warn("Suspect state FOUND. Matching by residence was neccessary but NO register-update are required!"); +        // no update required. Data can be used as it is. +        MatchingTaskUtils.storeFinalMatchingResult(pendingReq, +            MatchedPersonResult.generateFormMatchingResult( +                residencyResult.getResult(), eidasData.getCitizenCountryCode())); +                } - +                  } catch (WorkflowException e) {        throw new TaskExecutionException(pendingReq, "Search failed", new ManualFixNecessaryException(eidasData));      }    } -  private void moveToNextTask(ExecutionContext executionContext) { -    // Later on, this should transition to Step 20 -    executionContext.put(Constants.TRANSITION_TO_CREATE_NEW_ERNP_ENTRY_TASK, true); - -  } - -  private @NotNull UserInput parseHtmlInput(HttpServletRequest request) { +  private @NotNull AdresssucheOutput parseHtmlInput(HttpServletRequest request) {      Enumeration<String> reqParamNames = request.getParameterNames(); -    UserInput result = new UserInput(); +    AdresssucheOutputBuilder resultBuilder = AdresssucheOutput.builder();      while (reqParamNames.hasMoreElements()) {        final String paramName = reqParamNames.nextElement();        String escaped = StringEscapeUtils.escapeHtml(request.getParameter(paramName)); -      if (PARAM_FORMER_RESIDENCE_AVAILABLE.equalsIgnoreCase(paramName)) { -        result.setFormerResidenceAvailable(Boolean.parseBoolean(escaped)); +      if (AdresssucheController.PARAM_MUNIPICALITY.equalsIgnoreCase(paramName)) { +        resultBuilder.municipality(escaped); -      } else if (PARAM_STREET.equalsIgnoreCase(paramName)) { -        result.setStreet(escaped); +      } else if (AdresssucheController.PARAM_NUMBER.equalsIgnoreCase(paramName)) { +        resultBuilder.number(escaped); -      } else if (PARAM_CITY.equalsIgnoreCase(paramName)) { -        result.setCity(escaped); +      } else if (AdresssucheController.PARAM_POSTLEITZAHL.equalsIgnoreCase(paramName)) { +        resultBuilder.postleitzahl(escaped); -      } else if (PARAM_ZIPCODE.equalsIgnoreCase(paramName)) { -        result.setZipcode(escaped); +      } else if (AdresssucheController.PARAM_STREET.equalsIgnoreCase(paramName)) { +        resultBuilder.street(escaped); + +      } else if (AdresssucheController.PARAM_VILLAGE.equalsIgnoreCase(paramName)) { +        resultBuilder.village(escaped);        }      } -    return result; - +     +    return resultBuilder.build();        }  } diff --git a/eidas_modules/authmodule-eIDAS-v2/src/main/resources/messages/eidas_connector_message.properties b/eidas_modules/authmodule-eIDAS-v2/src/main/resources/messages/eidas_connector_message.properties index 188c5a8f..f1bf2128 100644 --- a/eidas_modules/authmodule-eIDAS-v2/src/main/resources/messages/eidas_connector_message.properties +++ b/eidas_modules/authmodule-eIDAS-v2/src/main/resources/messages/eidas_connector_message.properties @@ -23,5 +23,9 @@ module.eidasauth.matching.04=An error occurred while loading your data from offi  module.eidasauth.matching.11=Matching failed, because of an ERnP communication error. Reason: {0}  module.eidasauth.matching.12=Matching failed, because ERnP response contains historic information which is not supported. +module.eidasauth.matching.20=Matching be using residence information was canceled. Use another method for matching or create a new Austrian identity.   +module.eidasauth.matching.21=Matching be using residence information failed by missing input information. Use another method for matching or create a new Austrian identity.  +module.eidasauth.matching.22=Can not find an unique match by using residence information. Provide more or other data, use another method for matching, or create a new Austrian identity. +  module.eidasauth.matching.99=Matching failed, because of an unexpected processing error. Reason: {0} diff --git a/eidas_modules/authmodule-eIDAS-v2/src/test/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/test/tasks/ReceiveAustrianResidenceGuiResponseTaskTest.java b/eidas_modules/authmodule-eIDAS-v2/src/test/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/test/tasks/ReceiveAustrianResidenceGuiResponseTaskTest.java index 64bb0d48..15edce07 100644 --- a/eidas_modules/authmodule-eIDAS-v2/src/test/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/test/tasks/ReceiveAustrianResidenceGuiResponseTaskTest.java +++ b/eidas_modules/authmodule-eIDAS-v2/src/test/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/test/tasks/ReceiveAustrianResidenceGuiResponseTaskTest.java @@ -1,14 +1,9 @@  package at.asitplus.eidas.specific.modules.auth.eidas.v2.test.tasks; -import static at.asitplus.eidas.specific.modules.auth.eidas.v2.tasks.ReceiveAustrianResidenceGuiResponseTask.PARAM_CITY; -import static at.asitplus.eidas.specific.modules.auth.eidas.v2.tasks.ReceiveAustrianResidenceGuiResponseTask.PARAM_FORMER_RESIDENCE_AVAILABLE; -import static at.asitplus.eidas.specific.modules.auth.eidas.v2.tasks.ReceiveAustrianResidenceGuiResponseTask.PARAM_STREET; -import static at.asitplus.eidas.specific.modules.auth.eidas.v2.tasks.ReceiveAustrianResidenceGuiResponseTask.PARAM_ZIPCODE;  import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull;  import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertThrows;  import static org.mockito.ArgumentMatchers.eq; -import static org.springframework.util.Assert.isInstanceOf;  import java.math.BigInteger;  import java.util.Arrays; @@ -21,7 +16,6 @@ import org.junit.Before;  import org.junit.Test;  import org.junit.runner.RunWith;  import org.mockito.Mockito; -import org.mockito.MockitoAnnotations;  import org.springframework.beans.factory.annotation.Autowired;  import org.springframework.boot.test.mock.mockito.MockBean;  import org.springframework.context.i18n.LocaleContextHolder; @@ -36,21 +30,22 @@ import com.google.common.collect.Lists;  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.controller.AdresssucheController; +import at.asitplus.eidas.specific.modules.auth.eidas.v2.controller.AdresssucheController.AdresssucheOutput; +import at.asitplus.eidas.specific.modules.auth.eidas.v2.dao.MatchedPersonResult;  import at.asitplus.eidas.specific.modules.auth.eidas.v2.dao.RegisterResult;  import at.asitplus.eidas.specific.modules.auth.eidas.v2.dao.SimpleEidasData; -import at.asitplus.eidas.specific.modules.auth.eidas.v2.exception.ManualFixNecessaryException;  import at.asitplus.eidas.specific.modules.auth.eidas.v2.service.RegisterSearchService;  import at.asitplus.eidas.specific.modules.auth.eidas.v2.service.RegisterSearchService.RegisterOperationStatus;  import at.asitplus.eidas.specific.modules.auth.eidas.v2.service.RegisterSearchService.RegisterStatusResults;  import at.asitplus.eidas.specific.modules.auth.eidas.v2.tasks.ReceiveAustrianResidenceGuiResponseTask; -import at.asitplus.eidas.specific.modules.auth.eidas.v2.tasks.ReceiveAustrianResidenceGuiResponseTask.UserInput;  import at.asitplus.eidas.specific.modules.auth.eidas.v2.utils.MatchingTaskUtils;  import at.gv.egiz.eaaf.core.api.idp.process.ExecutionContext;  import at.gv.egiz.eaaf.core.exceptions.EaafStorageException; -import at.gv.egiz.eaaf.core.exceptions.TaskExecutionException;  import at.gv.egiz.eaaf.core.impl.idp.auth.data.AuthProcessDataWrapper;  import at.gv.egiz.eaaf.core.impl.idp.module.test.TestRequestImpl;  import at.gv.egiz.eaaf.core.impl.idp.process.ExecutionContextImpl; +import lombok.SneakyThrows;  @RunWith(SpringJUnit4ClassRunner.class)  @ContextConfiguration(locations = { @@ -67,7 +62,7 @@ public class ReceiveAustrianResidenceGuiResponseTaskTest {    private ReceiveAustrianResidenceGuiResponseTask task; -  private final ExecutionContext executionContext = new ExecutionContextImpl(); +  private ExecutionContext executionContext;    private MockHttpServletRequest httpReq;    private MockHttpServletResponse httpResp;    private TestRequestImpl pendingReq; @@ -79,8 +74,9 @@ public class ReceiveAustrianResidenceGuiResponseTaskTest {     */    @Before    public void setUp() throws Exception { +    executionContext = new ExecutionContextImpl();      task = new ReceiveAustrianResidenceGuiResponseTask(registerSearchService); - +          httpReq = new MockHttpServletRequest("POST", "https://localhost/ms_connector");      httpResp = new MockHttpServletResponse();      RequestContextHolder.resetRequestAttributes(); @@ -94,8 +90,26 @@ public class ReceiveAustrianResidenceGuiResponseTaskTest {    }    @Test +  public void canceledByUser() throws Exception { +    AdresssucheOutput userInput = setupUserInput(); +    SimpleEidasData eidasData = setupEidasData(); +    RegisterStatusResults registerSearchResult = buildEmptyResult(); +    mockRegisterSearch(userInput, registerSearchResult, eidasData); +    MatchingTaskUtils.storeIntermediateMatchingResult(pendingReq, registerSearchResult); +    httpReq.setParameter(ReceiveAustrianResidenceGuiResponseTask.HTTP_PARAM_NO_RESIDENCE, "true"); +     +    task.execute(pendingReq, executionContext); + +    assertEquals("Transition To S9", true, executionContext.get(Constants.TRANSITION_TO_GENERATE_OTHER_LOGIN_METHOD_GUI_TASK)); +    assertEquals("matching failed flag", true, executionContext.get(Constants.CONTEXT_FLAG_ADVANCED_MATCHING_FAILED)); +    assertEquals("failed reason", "module.eidasauth.matching.20", executionContext.get(Constants.CONTEXT_FLAG_ADVANCED_MATCHING_FAILED_REASON));     +    assertNull("no final matching result", MatchingTaskUtils.getFinalMatchingResult(pendingReq)); +     +  } +   +  @Test    public void noRegisterResult() throws Exception { -    UserInput userInput = setupUserInput(); +    AdresssucheOutput userInput = setupUserInput();      SimpleEidasData eidasData = setupEidasData();      RegisterStatusResults registerSearchResult = buildEmptyResult();      mockRegisterSearch(userInput, registerSearchResult, eidasData); @@ -103,56 +117,86 @@ public class ReceiveAustrianResidenceGuiResponseTaskTest {      task.execute(pendingReq, executionContext); -    assertEquals("Transition To S9", true, executionContext.get(Constants.TRANSITION_TO_CREATE_NEW_ERNP_ENTRY_TASK)); +    assertEquals("Transition To S9", true, executionContext.get(Constants.TRANSITION_TO_GENERATE_OTHER_LOGIN_METHOD_GUI_TASK)); +    assertEquals("matching failed flag", true, executionContext.get(Constants.CONTEXT_FLAG_ADVANCED_MATCHING_FAILED)); +    assertEquals("failed reason", "module.eidasauth.matching.22", executionContext.get(Constants.CONTEXT_FLAG_ADVANCED_MATCHING_FAILED_REASON)); +    assertNull("no final matching result", MatchingTaskUtils.getFinalMatchingResult(pendingReq)); +        }    @Test -  public void exactlyOneRegisterResult_Matching() throws Exception { -    UserInput userInput = setupUserInput(); +  public void exactlyOneRegisterResult_NoUpdate() throws Exception { +    AdresssucheOutput userInput = setupUserInput();      SimpleEidasData eidasData = setupEidasData();      RegisterStatusResults registerSearchResult = buildResultWithOneMatch(buildMatchingRegisterResult(eidasData));      MatchingTaskUtils.storeIntermediateMatchingResult(pendingReq, registerSearchResult);      mockRegisterSearch(userInput, registerSearchResult, eidasData);      task.execute(pendingReq, executionContext); - +         +    // validate state      assertNull("Transition To S9", executionContext.get(Constants.TRANSITION_TO_CREATE_NEW_ERNP_ENTRY_TASK)); -    Mockito.verify(registerSearchService).step7aKittProcess(eq(registerSearchResult), eq(eidasData)); - +    MatchedPersonResult matchingResult = MatchingTaskUtils.getFinalMatchingResult(pendingReq); +    assertNotNull("no final matching result", matchingResult); +    validateMatchedPerson(matchingResult, registerSearchResult);   +        }    @Test -  public void exactlyOneRegisterResult_NotMatching() throws Exception { -    UserInput userInput = setupUserInput(); +  public void exactlyOneRegisterResult_UpdateRequired() throws Exception { +    AdresssucheOutput userInput = setupUserInput();      SimpleEidasData eidasData = setupEidasData();      RegisterStatusResults registerSearchResult = buildResultWithOneMatch(buildNotMatchingRegisterResult(eidasData)); +    RegisterStatusResults registerUpdateResult = buildResultWithOneMatch(buildRandomRegisterResult());      MatchingTaskUtils.storeIntermediateMatchingResult(pendingReq, registerSearchResult);      mockRegisterSearch(userInput, registerSearchResult, eidasData); - +    Mockito.when(registerSearchService.step7aKittProcess(eq(registerSearchResult), eq(eidasData))) +        .thenReturn(registerUpdateResult); +         +    // perform test      task.execute(pendingReq, executionContext); -    assertEquals("Transition To S9", true, executionContext.get(Constants.TRANSITION_TO_CREATE_NEW_ERNP_ENTRY_TASK)); +    // validate state +    assertNull("Transition To S9", executionContext.get(Constants.TRANSITION_TO_CREATE_NEW_ERNP_ENTRY_TASK)); +             +    MatchedPersonResult matchingResult = MatchingTaskUtils.getFinalMatchingResult(pendingReq); +    assertNotNull("no final matching result", matchingResult); +    validateMatchedPerson(matchingResult, registerUpdateResult);        +        }    @Test    public void moreThanOneRegisterResult() throws Exception { -    UserInput userInput = setupUserInput(); +    AdresssucheOutput userInput = setupUserInput();      SimpleEidasData eidasData = setupEidasData();      RegisterStatusResults registerSearchResult = buildResultWithTwoMatches();      MatchingTaskUtils.storeIntermediateMatchingResult(pendingReq, registerSearchResult);      mockRegisterSearch(userInput, registerSearchResult, eidasData); -    TaskExecutionException e = assertThrows(TaskExecutionException.class, -        () -> task.execute(pendingReq, executionContext)); +    task.execute(pendingReq, executionContext); -    assertEquals(pendingReq.getPendingRequestId(), e.getPendingRequestID()); -    isInstanceOf(ManualFixNecessaryException.class, e.getOriginalException()); -    assertNull("Transition To S16", executionContext.get(Constants.TRANSITION_TO_CREATE_NEW_ERNP_ENTRY_TASK)); +    assertEquals("Transition To S9", true, executionContext.get(Constants.TRANSITION_TO_GENERATE_OTHER_LOGIN_METHOD_GUI_TASK)); +    assertEquals("matching failed flag", true, executionContext.get(Constants.CONTEXT_FLAG_ADVANCED_MATCHING_FAILED)); +    assertEquals("failed reason", "module.eidasauth.matching.22", executionContext.get(Constants.CONTEXT_FLAG_ADVANCED_MATCHING_FAILED_REASON)); +    assertNull("no final matching result", MatchingTaskUtils.getFinalMatchingResult(pendingReq)); +        } -  private void mockRegisterSearch(UserInput userInput, RegisterStatusResults registerSearchResult, SimpleEidasData eidasData ) { +  @SneakyThrows +  private void validateMatchedPerson(MatchedPersonResult current, +      RegisterStatusResults registerUpdateResult) {    +    RegisterResult expected = registerUpdateResult.getResult();     +    assertEquals("familyName", expected.getFamilyName(), current.getFamilyName()); +    assertEquals("givenName", expected.getGivenName(), current.getGivenName()); +    assertEquals("birthday", expected.getDateOfBirth(), current.getDateOfBirth()); +    assertEquals("bpk", expected.getBpk(), current.getBpk()); +     +  } +   +  @SneakyThrows +  private void mockRegisterSearch(AdresssucheOutput userInput, RegisterStatusResults registerSearchResult, SimpleEidasData eidasData ) {      Mockito.when(registerSearchService.searchWithResidence(eq(registerSearchResult.getOperationStatus()), eq(eidasData), -        eq(userInput.getZipcode()), eq(userInput.getCity()), eq(userInput.getStreet()))).thenReturn(registerSearchResult); +        eq(userInput))).thenReturn(registerSearchResult);    }    @NotNull @@ -216,11 +260,13 @@ public class ReceiveAustrianResidenceGuiResponseTaskTest {    } -  private void setHttpParameters(UserInput input) { -    httpReq.setParameter(PARAM_FORMER_RESIDENCE_AVAILABLE, String.valueOf(input.isFormerResidenceAvailable())); -    httpReq.setParameter(PARAM_STREET, input.getStreet()); -    httpReq.setParameter(PARAM_CITY, input.getCity()); -    httpReq.setParameter(PARAM_ZIPCODE, input.getZipcode()); +  private void setHttpParameters(AdresssucheOutput input) { +    httpReq.setParameter(AdresssucheController.PARAM_STREET, input.getStreet()); +    httpReq.setParameter(AdresssucheController.PARAM_MUNIPICALITY, input.getMunicipality()); +    httpReq.setParameter(AdresssucheController.PARAM_NUMBER, input.getNumber()); +    httpReq.setParameter(AdresssucheController.PARAM_VILLAGE, input.getVillage()); +    httpReq.setParameter(AdresssucheController.PARAM_POSTLEITZAHL, input.getPostleitzahl()); +        }    @NotNull @@ -237,8 +283,13 @@ public class ReceiveAustrianResidenceGuiResponseTaskTest {    }    @NotNull -  private UserInput setupUserInput() { -    UserInput result = new UserInput(true, RandomStringUtils.randomAlphabetic(8), RandomStringUtils.randomAlphabetic(8), RandomStringUtils.randomAlphabetic(8)); +  private AdresssucheOutput setupUserInput() { +    AdresssucheOutput result = new AdresssucheOutput( +        RandomStringUtils.randomAlphabetic(8),  +        RandomStringUtils.randomAlphabetic(8),  +        RandomStringUtils.randomAlphabetic(8), +        RandomStringUtils.randomAlphabetic(8), +        RandomStringUtils.randomAlphabetic(8));      setHttpParameters(result);      return result;    } | 
