static HttpUriRequest modifyOutboundRequest()

in gateway-service-nifi/src/main/java/org/apache/knox/gateway/dispatch/NiFiRequestUtil.java [34:89]


  static HttpUriRequest modifyOutboundRequest(HttpUriRequest outboundRequest, HttpServletRequest inboundRequest) throws IOException {
    // preserve trailing slash from inbound request in the outbound request
    if (inboundRequest.getPathInfo().endsWith("/")) {
      String[] split = outboundRequest.getURI().toString().split("\\?");
      if (!split[0].endsWith("/")) {
        outboundRequest = RequestBuilder.copy(outboundRequest).setUri(split[0] + "/" + (split.length == 2 ? "?" + split[1] : "")).build();
      }
    }
    // update the X-Forwarded-Context header to include the Knox-specific context path
    final Header originalXForwardedContextHeader = outboundRequest.getFirstHeader(NiFiHeaders.X_FORWARDED_CONTEXT);
    if (originalXForwardedContextHeader != null) {
      String xForwardedContextHeaderValue = originalXForwardedContextHeader.getValue();
      if (xForwardedContextHeaderValue != null && !xForwardedContextHeaderValue.isEmpty() && !xForwardedContextHeaderValue.contains("nifi-app")) {
        // Inspect the inbound request and outbound request to determine the additional context path from the rewrite
        // rules that needs to be added to the X-Forwarded-Context header to allow proper proxying to NiFi.
        //
        // NiFi does its own URL rewriting, and will not work with the context path provided by Knox
        // (ie, "/gateway/sandbox").
        //
        // For example, if Knox has a rewrite rule "*://*:*/**/nifi-app/{**}?{**}", "/nifi-app" needs to be added
        // to the existing value of the X-Forwarded-Context header, which ends up being "/gateway/sandbox/nifi-app".
        String inboundRequestPathInfo = inboundRequest.getPathInfo();
        String outboundRequestUriPath = outboundRequest.getURI().getPath();
        String outboundRequestUriPathNoTrailingSlash = StringUtils.removeEnd(outboundRequestUriPath, "/");
        String knoxRouteContext = null;
        int index = inboundRequestPathInfo.lastIndexOf(outboundRequestUriPathNoTrailingSlash);
        if (index >= 0) {
          knoxRouteContext = inboundRequestPathInfo.substring(0, index);
        } else {
          LogManager.getLogger(NiFiRequestUtil.class.getName()).error(String.format(Locale.ROOT, "Unable to find index of %s in %s", outboundRequestUriPathNoTrailingSlash, inboundRequestPathInfo));
        }
        outboundRequest.setHeader(NiFiHeaders.X_FORWARDED_CONTEXT, xForwardedContextHeaderValue + knoxRouteContext);
      }
    }

    // NiFi requires the header "X-ProxiedEntitiesChain" to be set with the identity or identities of the authenticated requester.
    // The effective principal (identity) in the requester subject must be added to "X-ProxiedEntitiesChain".
    // If the request already has a populated "X-ProxiedEntitiesChain" header, the identities must be appended to it.
    // If the user proxied through Knox is anonymous, the "Anonymous" identity needs to be represented in X-ProxiedEntitiesChain
    // as empty angle brackets "<>".
    final Subject subject = SubjectUtils.getCurrentSubject();
    String effectivePrincipalName = SubjectUtils.getEffectivePrincipalName(subject);
    String proxiedEntitesChainHeader = inboundRequest.getHeader(NiFiHeaders.X_PROXIED_ENTITIES_CHAIN);
    if(proxiedEntitesChainHeader == null) {
      proxiedEntitesChainHeader = "";
    }
    outboundRequest.setHeader(NiFiHeaders.X_PROXIED_ENTITIES_CHAIN, proxiedEntitesChainHeader +
        String.format(Locale.ROOT, "<%s>", "anonymous".equalsIgnoreCase(effectivePrincipalName) ? "" : effectivePrincipalName));

    // Make sure headers named "Cookie" are removed from the request to NiFi, since NiFi does not use cookies.
    Header[] cookieHeaders = outboundRequest.getHeaders("Cookie");
    for (Header cookieHeader : cookieHeaders) {
      outboundRequest.removeHeader(cookieHeader);
    }
    return outboundRequest;
  }