diff options
3 files changed, 256 insertions, 171 deletions
| diff --git a/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/controller/AbstractController.java b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/controller/AbstractController.java index c09efc37..dd113907 100644 --- a/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/controller/AbstractController.java +++ b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/controller/AbstractController.java @@ -21,16 +21,11 @@ package at.gv.egiz.eaaf.core.impl.idp.controller;  import java.io.IOException; +import javax.annotation.Nonnull; +import javax.annotation.Nullable;  import javax.servlet.http.HttpServletRequest;  import javax.servlet.http.HttpServletResponse; -import org.apache.commons.text.StringEscapeUtils; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.context.ApplicationContext; -import org.springframework.web.bind.annotation.ExceptionHandler; -  import at.gv.egiz.components.eventlog.api.EventConstants;  import at.gv.egiz.eaaf.core.api.IRequest;  import at.gv.egiz.eaaf.core.api.IStatusMessenger; @@ -44,9 +39,17 @@ import at.gv.egiz.eaaf.core.exceptions.EaafException;  import at.gv.egiz.eaaf.core.exceptions.PendingReqIdValidationException;  import at.gv.egiz.eaaf.core.exceptions.ProcessExecutionException;  import at.gv.egiz.eaaf.core.exceptions.TaskExecutionException; +import at.gv.egiz.eaaf.core.impl.data.Pair;  import at.gv.egiz.eaaf.core.impl.utils.Random;  import at.gv.egiz.eaaf.core.impl.utils.ServletUtils; +import org.apache.commons.text.StringEscapeUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.ApplicationContext; +import org.springframework.web.bind.annotation.ExceptionHandler; +  /**   * Basic application controller that implements core error-handling.   * @@ -142,6 +145,65 @@ public abstract class AbstractController {        final HttpServletRequest req, final HttpServletResponse resp, IRequest pendingReq)        throws IOException, EaafException { +    final Pair<IRequest, Throwable> errorToHandle = +        exractExceptionThatShouldBeLogged(pendingReq, exceptionThrown); + +    try { +      final String errorKey = storeErrorAndGetErrorToken(errorToHandle); + +      // build up redirect URL +      final String redirectUrl = generateErrorRedirectUrl(req, errorKey); +      resp.setContentType("text/html"); +      resp.setStatus(302); + +      resp.addHeader("Location", redirectUrl); +      log.debug("REDIRECT TO: " + redirectUrl); + +      return; + +    } catch (final Exception e) { +      log.warn("Default error-handling FAILED. Exception can not be stored ....", e); +      log.info("Switch to generic generic backup error-handling ... "); +      protAuthService.handleErrorNoRedirect(errorToHandle.getSecond(), req, resp, true); + +    } + +  } + +  protected String generateErrorRedirectUrl(final HttpServletRequest req, String errorKey) { +    String redirectUrl = null; +    redirectUrl = ServletUtils.getBaseUrl(req); +    redirectUrl += "/" + ProtocolFinalizationController.ENDPOINT_ERRORHANDLING + "?" +        + EaafConstants.PARAM_HTTP_ERROR_CODE + "=" + errorKey; +    return redirectUrl; + +  } + +  protected String storeErrorAndGetErrorToken(Pair<IRequest, Throwable> errorToHandle) throws EaafException { +    // log error directly in debug mode +    if (log.isDebugEnabled()) { +      log.warn(errorToHandle.getSecond().getMessage(), errorToHandle.getSecond()); +    } + +    // put exception into transaction store for redirect +    final String errorKey = Random.nextLongRandom(); +    if (errorToHandle.getFirst() != null) { +      revisionsLogger.logEvent(errorToHandle.getFirst(), EventConstants.TRANSACTION_ERROR); +      transactionStorage.put(errorKey, new ExceptionContainer(errorToHandle.getFirst(), errorToHandle +          .getSecond()), -1); + +    } else { +      transactionStorage.put(errorKey, new ExceptionContainer(null, errorToHandle.getSecond()), -1); + +    } + +    return errorKey; + +  } + +  @Nonnull +  protected Pair<IRequest, Throwable> exractExceptionThatShouldBeLogged( +      @Nullable IRequest pendingReq, @Nonnull Throwable exceptionThrown) {      Throwable loggedException = null;      final Throwable extractedException =          extractOriginalExceptionFromProcessException(exceptionThrown); @@ -155,8 +217,10 @@ public abstract class AbstractController {      } else if (exceptionThrown instanceof PendingReqIdValidationException) {        log.trace(            "Find pendingRequestId validation exception. Looking for invalid pending-request ... "); +        if (((PendingReqIdValidationException) exceptionThrown).getInvalidPendingReq() != null) {          pendingReq = ((PendingReqIdValidationException) exceptionThrown).getInvalidPendingReq(); +        }      } @@ -164,49 +228,11 @@ public abstract class AbstractController {      // use TaskExecutionException directly, if no Original Exeception is included      if (loggedException == null) {        loggedException = exceptionThrown; -    } - -    try { -      // switch to protocol-finalize method to generate a protocol-specific error -      // message - -      // log error directly in debug mode -      if (log.isDebugEnabled()) { -        log.warn(loggedException.getMessage(), loggedException); -      } - -      // put exception into transaction store for redirect -      final String key = Random.nextLongRandom(); -      if (pendingReq != null) { -        revisionsLogger.logEvent(pendingReq, EventConstants.TRANSACTION_ERROR); -        transactionStorage.put(key, new ExceptionContainer(pendingReq, loggedException), -1); - -      } else { -        transactionStorage.put(key, new ExceptionContainer(null, loggedException), -1); - -      } - -      // build up redirect URL -      String redirectUrl = null; -      redirectUrl = ServletUtils.getBaseUrl(req); -      redirectUrl += "/" + ProtocolFinalizationController.ENDPOINT_ERRORHANDLING + "?" -          + EaafConstants.PARAM_HTTP_ERROR_CODE + "=" + key; - -      resp.setContentType("text/html"); -      resp.setStatus(302); - -      resp.addHeader("Location", redirectUrl); -      log.debug("REDIRECT TO: " + redirectUrl); - -      return; - -    } catch (final Exception e) { -      log.warn("Default error-handling FAILED. Exception can not be stored ....", e); -      log.info("Switch to generic generic backup error-handling ... "); -      protAuthService.handleErrorNoRedirect(loggedException, req, resp, true);      } +    return Pair.newInstance(pendingReq, loggedException); +    }    /** diff --git a/eaaf_modules/eaaf_module_auth_sl20/src/main/java/at/gv/egiz/eaaf/modules/auth/sl20/tasks/AbstractReceiveQualEidTask.java b/eaaf_modules/eaaf_module_auth_sl20/src/main/java/at/gv/egiz/eaaf/modules/auth/sl20/tasks/AbstractReceiveQualEidTask.java index 87dd6263..655cc2c6 100644 --- a/eaaf_modules/eaaf_module_auth_sl20/src/main/java/at/gv/egiz/eaaf/modules/auth/sl20/tasks/AbstractReceiveQualEidTask.java +++ b/eaaf_modules/eaaf_module_auth_sl20/src/main/java/at/gv/egiz/eaaf/modules/auth/sl20/tasks/AbstractReceiveQualEidTask.java @@ -1,28 +1,11 @@  package at.gv.egiz.eaaf.modules.auth.sl20.tasks;  import java.io.IOException; -import java.io.StringWriter; -import java.net.URISyntaxException; -import java.util.HashMap;  import java.util.Map; -import java.util.UUID;  import javax.servlet.http.HttpServletRequest;  import javax.servlet.http.HttpServletResponse; -import org.apache.commons.lang3.StringUtils; -import org.apache.http.client.utils.URIBuilder; -import org.apache.http.entity.ContentType; -import org.jose4j.base64url.Base64Url; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; - -import com.fasterxml.jackson.core.JsonParseException; -import com.fasterxml.jackson.databind.JsonNode; -import com.fasterxml.jackson.databind.node.ObjectNode; - -import at.gv.egiz.eaaf.core.api.data.EaafConstants;  import at.gv.egiz.eaaf.core.api.idp.process.ExecutionContext;  import at.gv.egiz.eaaf.core.exceptions.EaafAuthenticationException;  import at.gv.egiz.eaaf.core.exceptions.EaafStorageException; @@ -40,14 +23,21 @@ import at.gv.egiz.eaaf.modules.auth.sl20.exceptions.SlCommandoParserException;  import at.gv.egiz.eaaf.modules.auth.sl20.utils.IJoseTools;  import at.gv.egiz.eaaf.modules.auth.sl20.utils.JsonMapper;  import at.gv.egiz.eaaf.modules.auth.sl20.utils.SL20Constants; -import at.gv.egiz.eaaf.modules.auth.sl20.utils.SL20JsonBuilderUtils;  import at.gv.egiz.eaaf.modules.auth.sl20.utils.SL20JsonExtractorUtils; +import at.gv.egiz.eaaf.modules.auth.sl20.utils.SL20ResponseUtils; + +import org.apache.commons.lang3.StringUtils; +import org.jose4j.base64url.Base64Url; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; + +import com.fasterxml.jackson.core.JsonParseException; +import com.fasterxml.jackson.databind.JsonNode;  public abstract class AbstractReceiveQualEidTask extends AbstractAuthServletTask {    private static final Logger log = LoggerFactory.getLogger(AbstractReceiveQualEidTask.class); -  private static final String PATTERN_PENDING_REQ_ID = "#PENDINGREQID#"; -    @Autowired(required = true)    private IJoseTools joseTools; @@ -177,10 +167,14 @@ public abstract class AbstractReceiveQualEidTask extends AbstractAuthServletTask          // write SL2.0 response          if (sl20ReqObj != null) { -          // buildResponse(request, response, sl20ReqObj, aTrustErrorWorkAround); -          buildResponse(request, response, sl20ReqObj); +          final String resumeEndpoint = new DataUrlBuilder().buildDataUrl(pendingReq.getAuthUrl(), +              getResumeEndPoint(), pendingReq.getPendingRequestId()); +          SL20ResponseUtils.buildResponse(request, response, pendingReq, resumeEndpoint, +              SL20JsonExtractorUtils.getStringValue(sl20ReqObj, SL20Constants.SL20_TRANSACTIONID, false), +              authConfig); +          } else { -          buildErrorResponse(response, "2000", "General transport Binding error"); +          SL20ResponseUtils.buildErrorResponse(response, "2000", "General transport Binding error");          }        } @@ -213,106 +207,5 @@ public abstract class AbstractReceiveQualEidTask extends AbstractAuthServletTask    protected abstract String getResumeEndPoint(); -  private void buildErrorResponse(final HttpServletResponse response, final String errorCode, final String errorMsg) -      throws Exception { -    final ObjectNode error = SL20JsonBuilderUtils.createErrorCommandResult(errorCode, errorMsg); -    final ObjectNode errorCommand = SL20JsonBuilderUtils -        .createCommandResponse(SL20Constants.SL20_COMMAND_IDENTIFIER_ERROR, error, null); - -    final ObjectNode respContainer = SL20JsonBuilderUtils.createGenericResponse(UUID.randomUUID().toString(), null, -        null, errorCommand, null); - -    log.trace("SL20 response to VDA: " + respContainer); -    final StringWriter writer = new StringWriter(); -    writer.write(respContainer.toString()); -    final byte[] content = writer.toString().getBytes("UTF-8"); -    response.setStatus(HttpServletResponse.SC_OK); -    response.setContentLength(content.length); -    response.setContentType(ContentType.APPLICATION_JSON.toString()); -    response.getOutputStream().write(content); - -  } - -  private void buildResponse(final HttpServletRequest request, final HttpServletResponse response, -      final JsonNode sl20ReqObj) throws IOException, SL20Exception, URISyntaxException { -    // create response -    final Map<String, String> reqParameters = new HashMap<>(); -    reqParameters.put(EaafConstants.PARAM_HTTP_TARGET_PENDINGREQUESTID, pendingReq.getPendingRequestId()); -    final ObjectNode callReqParams = SL20JsonBuilderUtils.createCallCommandParameters( -        new DataUrlBuilder().buildDataUrl(pendingReq.getAuthUrl(), getResumeEndPoint(), null), -        SL20Constants.SL20_COMMAND_PARAM_GENERAL_CALL_METHOD_GET, false, reqParameters); -    final ObjectNode callCommand = SL20JsonBuilderUtils.createCommand(SL20Constants.SL20_COMMAND_IDENTIFIER_CALL, -        callReqParams); - -    // build first redirect command for app -    final ObjectNode redirectOneParams = SL20JsonBuilderUtils -        .createRedirectCommandParameters(generateIpcRedirectUrlForDebugging(), callCommand, null, true); -    final ObjectNode redirectOneCommand = SL20JsonBuilderUtils -        .createCommand(SL20Constants.SL20_COMMAND_IDENTIFIER_REDIRECT, redirectOneParams); - -    // build second redirect command for IDP -    final ObjectNode redirectTwoParams = SL20JsonBuilderUtils.createRedirectCommandParameters(new DataUrlBuilder() -        .buildDataUrl(pendingReq.getAuthUrl(), getResumeEndPoint(), pendingReq.getPendingRequestId()), -        redirectOneCommand, null, false); -    final ObjectNode redirectTwoCommand = SL20JsonBuilderUtils -        .createCommand(SL20Constants.SL20_COMMAND_IDENTIFIER_REDIRECT, redirectTwoParams); - -    // build generic SL2.0 response container -    final String transactionId = SL20JsonExtractorUtils.getStringValue(sl20ReqObj, SL20Constants.SL20_TRANSACTIONID, -        false); -    final ObjectNode respContainer = SL20JsonBuilderUtils.createGenericRequest(UUID.randomUUID().toString(), -        transactionId, redirectTwoCommand, null); - -    if (request.getHeader(SL20Constants.HTTP_HEADER_SL20_CLIENT_TYPE) != null && request -        .getHeader(SL20Constants.HTTP_HEADER_SL20_CLIENT_TYPE).equals(SL20Constants.HTTP_HEADER_VALUE_NATIVE)) { -      log.debug("Client request containts 'native client' header ... "); -      log.trace("SL20 response to VDA: " + respContainer); -      final StringWriter writer = new StringWriter(); -      writer.write(respContainer.toString()); -      final byte[] content = writer.toString().getBytes("UTF-8"); -      response.setStatus(HttpServletResponse.SC_OK); -      response.setContentLength(content.length); -      response.setContentType(ContentType.APPLICATION_JSON.toString()); -      response.getOutputStream().write(content); - -    } else { -      log.info("SL2.0 DataURL communication needs http header: '" + SL20Constants.HTTP_HEADER_SL20_CLIENT_TYPE + "'"); - -      log.debug("Client request containts is no native client ... "); -      final URIBuilder clientRedirectUri = new URIBuilder(new DataUrlBuilder().buildDataUrl(pendingReq.getAuthUrl(), -          getResumeEndPoint(), pendingReq.getPendingRequestId())); -      response.setStatus(Integer.parseInt(authConfig.getBasicConfiguration(Constants.CONFIG_PROP_HTTP_REDIRECT_CODE, -          Constants.CONFIG_PROP_HTTP_REDIRECT_CODE_DEFAULT_VALUE))); -      response.setHeader("Location", clientRedirectUri.build().toString()); - -      // throw new SL20Exception("sl20.06", -      // new Object[] {"SL2.0 DataURL communication needs http header: '" + -      // SL20Constants.HTTP_HEADER_SL20_CLIENT_TYPE + "'"}); - -    } -  } - -  /** -   * Generates a IPC redirect URL that is configured on IDP side. -   * -   * @return IPC ReturnURL, or null if no URL is configured -   */ -  private String generateIpcRedirectUrlForDebugging() { - -    String ipcRedirectUrlConfig = authConfig.getBasicConfiguration(Constants.CONFIG_PROP_IPC_RETURN_URL); -    if (StringUtils.isNotEmpty(ipcRedirectUrlConfig)) { -      if (ipcRedirectUrlConfig.contains(PATTERN_PENDING_REQ_ID)) { -        log.trace("Find 'pendingReqId' pattern in IPC redirect URL. Update url ... "); -        ipcRedirectUrlConfig = ipcRedirectUrlConfig.replaceAll("#PENDINGREQID#", -            EaafConstants.PARAM_HTTP_TARGET_PENDINGREQUESTID + "=" + pendingReq.getPendingRequestId()); - -      } - -      return ipcRedirectUrlConfig; -    } - -    return null; - -  }  } diff --git a/eaaf_modules/eaaf_module_auth_sl20/src/main/java/at/gv/egiz/eaaf/modules/auth/sl20/utils/SL20ResponseUtils.java b/eaaf_modules/eaaf_module_auth_sl20/src/main/java/at/gv/egiz/eaaf/modules/auth/sl20/utils/SL20ResponseUtils.java new file mode 100644 index 00000000..4bb91634 --- /dev/null +++ b/eaaf_modules/eaaf_module_auth_sl20/src/main/java/at/gv/egiz/eaaf/modules/auth/sl20/utils/SL20ResponseUtils.java @@ -0,0 +1,166 @@ +package at.gv.egiz.eaaf.modules.auth.sl20.utils; + +import java.io.IOException; +import java.io.StringWriter; +import java.net.URISyntaxException; +import java.net.URL; +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import at.gv.egiz.eaaf.core.api.IRequest; +import at.gv.egiz.eaaf.core.api.data.EaafConstants; +import at.gv.egiz.eaaf.core.api.idp.IConfiguration; +import at.gv.egiz.eaaf.modules.auth.sl20.Constants; +import at.gv.egiz.eaaf.modules.auth.sl20.exceptions.SL20Exception; + +import org.apache.commons.lang3.StringUtils; +import org.apache.http.client.utils.URIBuilder; +import org.apache.http.entity.ContentType; + +import com.fasterxml.jackson.databind.node.ObjectNode; +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public class SL20ResponseUtils { +  private static final String PATTERN_PENDING_REQ_ID = "#PENDINGREQID#"; + +  /** +   * Build a generic SL2.x error-response without redirect to AuthHandler. +   * +   * @param response http response object +   * @param errorCode ErrorCode +   * @param errorMsg Error message +   * @throws Exception In case of a message generation error +   */ +  public static void buildErrorResponse(final HttpServletResponse response, +      final String errorCode, final String errorMsg) +      throws Exception { +    final ObjectNode error = SL20JsonBuilderUtils.createErrorCommandResult(errorCode, errorMsg); +    final ObjectNode errorCommand = SL20JsonBuilderUtils +        .createCommandResponse(SL20Constants.SL20_COMMAND_IDENTIFIER_ERROR, error, null); + +    final ObjectNode respContainer = SL20JsonBuilderUtils.createGenericResponse(UUID.randomUUID().toString(), null, +        null, errorCommand, null); + +    log.trace("SL20 response to VDA: " + respContainer); +    final StringWriter writer = new StringWriter(); +    writer.write(respContainer.toString()); +    final byte[] content = writer.toString().getBytes("UTF-8"); +    response.setStatus(HttpServletResponse.SC_OK); +    response.setContentLength(content.length); +    response.setContentType(ContentType.APPLICATION_JSON.toString()); +    response.getOutputStream().write(content); + +  } + +  /** +   * Build a Security-Layer 2.x conform redirect response. +   * +   * @param request http request +   * @param response http response +   * @param pendingReq Current pending request +   * @param fullRedirectUrl Endpoint, where the auth. process should be resumed after redirect +   * @param transactionId SL2.0 transactionId if available +   * @param authConfig Basic application configuration +   * @throws IOException In case of a http servlet error +   * @throws SL20Exception In case of a SL2.0 request generation error +   * @throws URISyntaxException In case of an invalid Redirect URL +   */ +  public static void buildResponse(final HttpServletRequest request, final HttpServletResponse response, +      IRequest pendingReq, String fullRedirectUrl, String transactionId, IConfiguration authConfig) +          throws IOException, SL20Exception, URISyntaxException { +    // create response +    final Map<String, String> reqParameters = new HashMap<>(); + +    final URL redirectUrl = new URL(fullRedirectUrl); +    if (redirectUrl.getQuery() != null) { +      final String [] elements = redirectUrl.getQuery().split("&"); +      for (final String element : elements) { +        final String[] keyValue = element.split("="); +        if (keyValue.length == 2) { +          reqParameters.put(keyValue[0], keyValue[1]); + +        } else { +          log.warn("Ignore parameter with name: {}", keyValue[0]); + +        } +      } +    } + +    //reqParameters.put(EaafConstants.PARAM_HTTP_TARGET_PENDINGREQUESTID, pendingReq.getPendingRequestId()); + +    final ObjectNode callReqParams = SL20JsonBuilderUtils.createCallCommandParameters( +        fullRedirectUrl.split("\\?")[0], +        SL20Constants.SL20_COMMAND_PARAM_GENERAL_CALL_METHOD_GET, false, reqParameters); +    final ObjectNode callCommand = SL20JsonBuilderUtils.createCommand(SL20Constants.SL20_COMMAND_IDENTIFIER_CALL, +        callReqParams); + +    // build first redirect command for app +    final ObjectNode redirectOneParams = SL20JsonBuilderUtils +        .createRedirectCommandParameters(generateIpcRedirectUrlForDebugging( +            pendingReq, +            authConfig.getBasicConfiguration(Constants.CONFIG_PROP_IPC_RETURN_URL)), +            callCommand, null, true); +    final ObjectNode redirectOneCommand = SL20JsonBuilderUtils +        .createCommand(SL20Constants.SL20_COMMAND_IDENTIFIER_REDIRECT, redirectOneParams); + +    // build second redirect command for IDP +    final ObjectNode redirectTwoParams = SL20JsonBuilderUtils.createRedirectCommandParameters( +        fullRedirectUrl, +        redirectOneCommand, null, false); +    final ObjectNode redirectTwoCommand = SL20JsonBuilderUtils +        .createCommand(SL20Constants.SL20_COMMAND_IDENTIFIER_REDIRECT, redirectTwoParams); + +    // build generic SL2.0 response container +    final ObjectNode respContainer = SL20JsonBuilderUtils.createGenericRequest(UUID.randomUUID().toString(), +        transactionId, redirectTwoCommand, null); + +    if (request.getHeader(SL20Constants.HTTP_HEADER_SL20_CLIENT_TYPE) != null && request +        .getHeader(SL20Constants.HTTP_HEADER_SL20_CLIENT_TYPE).equals(SL20Constants.HTTP_HEADER_VALUE_NATIVE)) { +      log.debug("Client request containts 'native client' header ... "); +      log.trace("SL20 response to VDA: " + respContainer); +      final StringWriter writer = new StringWriter(); +      writer.write(respContainer.toString()); +      final byte[] content = writer.toString().getBytes("UTF-8"); +      response.setStatus(HttpServletResponse.SC_OK); +      response.setContentLength(content.length); +      response.setContentType(ContentType.APPLICATION_JSON.toString()); +      response.getOutputStream().write(content); + +    } else { +      log.info("SL2.0 DataURL communication needs http header: '" + SL20Constants.HTTP_HEADER_SL20_CLIENT_TYPE + "'"); + +      log.debug("Client request containts is no native client ... "); +      final URIBuilder clientRedirectUri = new URIBuilder(fullRedirectUrl); +      response.setStatus(Integer.parseInt(authConfig.getBasicConfiguration(Constants.CONFIG_PROP_HTTP_REDIRECT_CODE, +          Constants.CONFIG_PROP_HTTP_REDIRECT_CODE_DEFAULT_VALUE))); +      response.setHeader("Location", clientRedirectUri.build().toString()); + +    } +  } + +  /** +   * Generates a IPC redirect URL that is configured on IDP side. +   * +   * @return IPC ReturnURL, or null if no URL is configured +   */ +  private static String generateIpcRedirectUrlForDebugging(IRequest pendingReq, String ipcRedirectUrlConfig) { +    if (StringUtils.isNotEmpty(ipcRedirectUrlConfig)) { +      if (ipcRedirectUrlConfig.contains(PATTERN_PENDING_REQ_ID)) { +        log.trace("Find 'pendingReqId' pattern in IPC redirect URL. Update url ... "); +        ipcRedirectUrlConfig = ipcRedirectUrlConfig.replaceAll("#PENDINGREQID#", +            EaafConstants.PARAM_HTTP_TARGET_PENDINGREQUESTID + "=" + pendingReq.getPendingRequestId()); + +      } + +      return ipcRedirectUrlConfig; +    } + +    return null; + +  } +} | 
