Package com.adito.reverseproxy

Source Code of com.adito.reverseproxy.ReverseProxyMethodHandler

        /*
*  Adito
*
*  Copyright (C) 2003-2006 3SP LTD. All Rights Reserved
*
*  This program is free software; you can redistribute it and/or
*  modify it under the terms of the GNU General Public License
*  as published by the Free Software Foundation; either version 2 of
*  the License, or (at your option) any later version.
*  This program is distributed in the hope that it will be useful,
*  but WITHOUT ANY WARRANTY; without even the implied warranty of
*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
*  GNU General Public License for more details.
*
*  You should have received a copy of the GNU General Public
*  License along with this program; if not, write to the Free Software
*  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
     
package com.adito.reverseproxy;

import java.io.ByteArrayOutputStream;
import java.io.EOFException;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.UnknownHostException;
import java.util.Enumeration;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
import java.util.StringTokenizer;
import java.util.Vector;

import javax.servlet.http.Cookie;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import com.maverick.http.AuthenticationCancelledException;
import com.maverick.http.HttpAuthenticatorFactory;
import com.maverick.http.HttpClient;
import com.maverick.http.HttpException;
import com.maverick.http.HttpResponse;
import com.maverick.http.PasswordCredentials;
import com.maverick.http.UnsupportedAuthenticationException;
import com.maverick.util.URLUTF8Encoder;
import com.adito.boot.ContextHolder;
import com.adito.boot.HttpConstants;
import com.adito.boot.RequestHandler;
import com.adito.boot.RequestHandlerException;
import com.adito.boot.RequestHandlerRequest;
import com.adito.boot.RequestHandlerResponse;
import com.adito.boot.SystemProperties;
import com.adito.boot.Util;
import com.adito.core.MultiMap;
import com.adito.core.stringreplacement.SessionInfoReplacer;
import com.adito.core.stringreplacement.VariableReplacement;
import com.adito.policyframework.LaunchSession;
import com.adito.policyframework.LaunchSessionFactory;
import com.adito.security.Constants;
import com.adito.security.LogonControllerFactory;
import com.adito.security.SessionInfo;
import com.adito.util.ProxiedHttpMethod;
import com.adito.vfs.webdav.DAVUtilities;
import com.adito.webforwards.AbstractAuthenticatingWebForwardHandler;
import com.adito.webforwards.ReverseProxyWebForward;
import com.adito.webforwards.WebForwardPlugin;
import com.adito.webforwards.WebForwardTypes;

/**
* Request handler that deals with both <i>Reverse Proxy</i> and <i>Replacement
* Proxy</i> web forwards.
*/
public class ReverseProxyMethodHandler extends AbstractAuthenticatingWebForwardHandler implements RequestHandler {

  /**
   * Launch session attribute for storing whether authentication has been
   * posted yet
   */
  public static final String LAUNCH_ATTR_AUTH_POSTED = "authPosted";

  final static String sessionCookie = SystemProperties.get("adito.cookie", "JSESSIONID");

  static HashSet<String> ignoredHeaders = new HashSet<String>();

  static {
    ignoredHeaders.add("Location".toUpperCase());
    ignoredHeaders.add("Server".toUpperCase());
    ignoredHeaders.add("Date".toUpperCase());
  }

  static Log log = LogFactory.getLog(ReverseProxyMethodHandler.class);

  public boolean handle(String pathInContext, String pathParams, RequestHandlerRequest request, RequestHandlerResponse response)
          throws RequestHandlerException, IOException {
    if (log.isDebugEnabled())
      log.debug("Check if Reverse Proxy Request for: " + pathInContext);

    /*
     * First try and locate the session, if there is no session then this is
     * definitely not a reverse proxy request
     */
    LaunchSession launchSession = null;
    SessionInfo session = locateSession(request, response);

    if (session == null) {
      // If we have no session, then this cannot be a reverse proxy
      // request
      if (log.isDebugEnabled())
        log.debug("No session, not a reverse proxy.");
      return false;
    }
   
    try {
      // Perhaps this is a reverse proxy?
      String host = request.getHost();
      ReverseProxyWebForward wf = null;

      // Active Proxy

      if (host != null && !host.equals("") && host.indexOf('.') > -1) {
        int idx = host.indexOf('.');
        if (idx != -1) {
          try {
            String uniqueId = host.substring(0, idx);
            launchSession = LaunchSessionFactory.getInstance().getLaunchSession(session, uniqueId);
            if (launchSession != null) {
              wf = (ReverseProxyWebForward) launchSession.getResource();
              launchSession.checkAccessRights(null, session);
              if (!((ReverseProxyWebForward) wf).getActiveDNS()) {
                throw new Exception("Appears to be an active DNS request but the associated web forward is not active DNS. Is someone trying something funny???");
              }
                          LogonControllerFactory.getInstance().addCookies(request, response, session.getLogonTicket(), session);
              return handleReverseProxy(pathInContext, pathParams, request, response, launchSession);
            }

          } catch (Exception ex) {
            if (log.isDebugEnabled())
              log.debug("Active DNS web forward lookup failed", ex);
          }
        } else {
          if (log.isDebugEnabled())
            log.debug("Not active DNS.");
        }
      }

      String hostHeader = request.getHost();
      int idx = hostHeader.indexOf(':');
      if (idx > -1)
        hostHeader = hostHeader.substring(0, idx);

      /* Ordinary reverse proxy? There can only ever be one launch session per reverse proxy
       * as there is no way of maintaining the session across requests. If a user launches the
       * resource more than once, the old launch session will be removed
       */

      for (LaunchSession rs : LaunchSessionFactory.getInstance().getLaunchSessionsForType(session,
        WebForwardPlugin.WEBFORWARD_RESOURCE_TYPE)) {
        if (rs.getResource() instanceof ReverseProxyWebForward) {
          wf = (ReverseProxyWebForward) rs.getResource();
          // Check that its not reverseProxyRedirect.jsp because if we don't it breaks access after first attempt in same session
          if (wf.isValidPath(pathInContext) || (wf.getHostHeader() != null && wf.getHostHeader().equals(hostHeader) && !pathInContext.startsWith("/reverseProxyRedirect.jsp"))) {
            rs.checkAccessRights(null, session);
            return handleReverseProxy(pathInContext, pathParams, request, response, rs);
          }
        }
      }
    } catch (Exception e) {
      log.error("Failed to process web forward.", e);
      if (session != null) {
        session.getHttpSession().setAttribute(Constants.EXCEPTION, e);
        response.sendRedirect("/showPopupException.do");
      } else {
        throw new RequestHandlerException("Failed to process web forward.", 500);
      }
      return true;
    }
    return false;
  }

  private boolean handleReverseProxy(String path, String params, RequestHandlerRequest request, RequestHandlerResponse response,
                    LaunchSession launchSession) throws IOException {

    ReverseProxyWebForward webForward = (ReverseProxyWebForward) launchSession.getResource();
    boolean connectionError = true;
   
    /* Because we are in a request handler, the session's last access time
     * does not get updated by the container
     */
    launchSession.getSession().access();

    /***
     * LDP - DO NOT use request parameter map until the encoding has been set. If you
     * call getParameters it decodes the parameters so this can only be done once the
     * character set has been set.
     */

    try {
      URL target = getTarget(launchSession, request);
      setRequestEncoding(launchSession, target, request);
      HttpClient client = getClient(launchSession, target);
      ProxiedHttpMethod method = getMethod(client, launchSession, request, target);
      processPortsAndXForwarding(method, request);
      checkProcessedContent(launchSession, method, request);
      addCustomHeaders(webForward, method);
     
      /* If this webforward has JavaScript form authentication and this hasn't
       * yet been processed, then we make sure the content that comes back from
       * the target is not encoded using gzip or any other compression methods.
       * This is because we will be tacking on some content and its easy to
       * deal with unencoded.
       *
       * TODO We may want to support at least Gzip at some point
       */
      if (webForward.getFormType().equals(WebForwardTypes.FORM_SUBMIT_JAVASCRIPT)
          && !Boolean.TRUE.equals(launchSession.getAttribute(LAUNCH_ATTR_AUTH_POSTED))) {
        method.getProxiedRequest().removeFields("Accept-Encoding");
      }
     
      com.maverick.http.HttpResponse clientResponse = doExecute(client, method);
      connectionError = false;
      checkInsecureIIS(webForward, clientResponse);
      filterUnsupportedAuthMethods(clientResponse);
      processStatus(clientResponse, response);
      processRedirects(clientResponse, request, response);
      processHeaders(clientResponse, response);

      /*
       * If the content type is HTML, this webforward is configured for
       * automatic JavaScript authentication and authentication has not
       * yet been performed, then tack the JavaScript on to the end of the
       * content. This requires that the content is read into memory and
       * the content length adjusted
       */
      if (clientResponse.getStatus() == 200 && webForward.getFormType().equals(WebForwardTypes.FORM_SUBMIT_JAVASCRIPT)
        && "text/html".equals(clientResponse.getContentTypeWithoutParameter())
        && !Boolean.TRUE.equals(launchSession.getAttribute(LAUNCH_ATTR_AUTH_POSTED))) {
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        Util.copy(clientResponse.getInputStream(), baos, -1, 16384);
        addJavaScriptAuthenticationCode(launchSession, baos, 0);
        byte[] arr = baos.toByteArray();
        if (clientResponse.getHeaderField("Content-Length") != null) {
          response.setField("Content-Length", String.valueOf(arr.length));
        }
        response.getOutputStream().write(arr);
        launchSession.setAttribute(LAUNCH_ATTR_AUTH_POSTED, Boolean.TRUE);
      } else {
        Util.copy(clientResponse.getInputStream(), response.getOutputStream(), -1, 16384);
      }
     
      clientResponse.close();

      return true;
    } catch (UnsupportedAuthenticationException ex) {
      log.error("?", ex);
    } catch (com.maverick.http.HttpException ex) {
      log.error("?", ex);
    } catch (EOFException e) {
      /*
       * This is probably just because the user clicked on a link before
       * the page had finished downloading.
       */
      if (log.isDebugEnabled())
        log.debug("Received EOF in reverse proxy request [THIS IS PROBABLY NOT FATAL]", e);
    } catch (IOException ex) {
      if (connectionError) {
        response.sendError(404,
          "The proxied web server could not be contacted or did not respond correctly to the request! " + ex.getMessage());
      }
      log.error("?", ex);
    } catch (AuthenticationCancelledException ex) {
      log.error("?", ex);
    }
    return true;

  }

  HttpResponse doExecute(HttpClient client, ProxiedHttpMethod method) throws UnknownHostException, IOException,
          HttpException, UnsupportedAuthenticationException, AuthenticationCancelledException {
    if (log.isDebugEnabled()) {
      log.debug("Connecting to " + client.getHost() + ":" + client.getPort() + " (Secure = " + client.isSecure() + ")");
    }
    return client.execute(method);
  }

  URL getTarget(LaunchSession launchSession, RequestHandlerRequest request) throws MalformedURLException {
    ReverseProxyWebForward webForward = (ReverseProxyWebForward) launchSession.getResource();
    VariableReplacement r = new VariableReplacement();
    r.setRequest(request);
    r.setSession(launchSession.getSession());
    r.setPolicy(launchSession.getPolicy());

    URL target = new URL(r.replace(webForward.getDestinationURL()));

    if (log.isDebugEnabled()) {
      log.debug("Reverse proxy target  " + target.toExternalForm());
    }
    return target;
  }

  void checkProcessedContent(LaunchSession launchSession, ProxiedHttpMethod method, RequestHandlerRequest request)
          throws IOException {
    String contentType = request.getContentType();
    int contentLength = request.getContentLength();

    boolean hasProcessedContent = contentType != null && request.getMethod().equals("POST")
      && contentType.equals("application/x-www-form-urlencoded");

    if (contentLength > 0 && !hasProcessedContent) {
      if(log.isDebugEnabled())
        log.debug("Setting request content of " + contentLength + " bytes with content type " + contentType + " available=" + request.getInputStream().available());
      method.setContent(request.getInputStream(), contentLength, contentType);
    }

  }

  private void processRequestHeaders(RequestHandlerRequest request, ProxiedHttpMethod method) {
    String header;

    for (Enumeration e = request.getFieldNames(); e.hasMoreElements();) {
      header = (String) e.nextElement();

      // Skip the connection header as our client maintains its own
      // connections
      if (header.equalsIgnoreCase(HttpConstants.HDR_CONNECTION) || header.equalsIgnoreCase(HttpConstants.HDR_KEEP_ALIVE)) {
        continue;
      }

      for (Enumeration j = request.getFieldValues(header); j.hasMoreElements();) {
        String val = (String) j.nextElement();
        if (header.equalsIgnoreCase("cookie")) {
          String[] cookieVals = val.split("\\;");
          StringBuffer newVal = new StringBuffer();
          for (int i = 0; i < cookieVals.length; i++) {
            if (log.isDebugEnabled())
              log.debug("Cookie = " + cookieVals[i]);
           
            // Its possible cookies may be sent without values
            int idx = cookieVals[i].indexOf('=');
            String cn = idx == -1 ? cookieVals[i] : Util.trimBoth(cookieVals[i].substring(0, idx));
            String cv = idx == -1 ? null : Util.trimBoth(cookieVals[i].substring(idx + 1));
           
            // Ignore SSL-Exploer cookies
            if (cn.equals(Constants.LOGON_TICKET) || cn.equals(Constants.DOMAIN_LOGON_TICKET)
              || cn.equals(SystemProperties.get("adito.cookie", "SSLX_SSESHID"))) {
              if (log.isDebugEnabled())
                log.debug("  Omiting cookie " + cn + "=" + cv);
            } else {
              if (newVal.length() > 0) {
                newVal.append("; ");
              }
              newVal.append(cn);
              if(cv != null) {
                newVal.append("=");
                newVal.append(cv);
              }
            }
          }
          if (newVal.length() > 0) {
            method.getProxiedRequest().addHeaderField(header, newVal.toString());
            if (log.isDebugEnabled())
              log.debug("HEADER: " + header + " " + val);
          }
        } else {
          method.getProxiedRequest().addHeaderField(header, val);
          if (log.isDebugEnabled())
            log.debug("HEADER: " + header + " " + val);
        }
      }
    }

  }

  void processPortsAndXForwarding(ProxiedHttpMethod method, RequestHandlerRequest request) {

    String thisHost = ContextHolder.getContext().getHostname();
    int thisPort = ContextHolder.getContext().getPort();

    // Check for a non default port (we dont care if we receive on 443
    // but
    // forward to 80 as this would not change the host header
    if (thisPort != 443 && thisPort != 80) {
      thisHost += ":" + thisPort;
    }

    method.getProxiedRequest().setHeaderField("X-Forwarded-Host", thisHost);
    method.getProxiedRequest().setHeaderField("X-Forwarded-For", request.getRemoteHost());
    method.getProxiedRequest().setHeaderField("X-Forwarded-Server", thisHost);
    method.getProxiedRequest().setHeaderField("X-Forwarded-Port", String.valueOf(thisPort));

  }

  void processStatus(HttpResponse clientResponse, RequestHandlerResponse response) {

    if (log.isDebugEnabled())
      log.debug("HTTP response is " + clientResponse.getStartLine());

    response.setStatus(clientResponse.getStatus());
    response.setReason(clientResponse.getReason());

  }

  void processHeaders(HttpResponse clientResponse, RequestHandlerResponse response) {

    String header;
    for (Enumeration e = clientResponse.getHeaderFieldNames(); e.hasMoreElements();) {
      header = (String) e.nextElement();
      if (log.isDebugEnabled()) {
        log.debug("Received header " + header);
      }
      String[] val = clientResponse.getHeaderFields(header);
      if(val == null) {
        log.debug("No value???");
      }

      if (ignoredHeaders.contains(header.toUpperCase())) {
        if (log.isDebugEnabled())
          log.debug("Ignoring header " + header);
        continue;
      }

      for (int i = 0; i < val.length; i++) {
        if (log.isDebugEnabled()) {
          log.debug("Adding value " + val[i] + " for " + header);
        }
        if (i == 0)
          response.setField(header, val[i]);
        else
          response.addField(header, val[i]);
      }
    }
  }

  void processRedirects(HttpResponse clientResponse, RequestHandlerRequest request, RequestHandlerResponse response) {

    /**
     * Process redirect Location headers, the location may be a HTTP
     * resource which will require changing to HTTPS
     */
    if (clientResponse.getStatus() >= 300 && clientResponse.getStatus() < 400) {
      switch (clientResponse.getStatus()) {
        case 300: // Multiple choices
        case 301: // Moved permanentley
        case 302: // Found
        case 303: // See other
        case 307: // Temporarily redirect
          String[] locations = clientResponse.getHeaderFields(HttpConstants.HDR_LOCATION);
          response.removeField(HttpConstants.HDR_LOCATION);
          for (int i = 0; i < locations.length; i++) {
                        String originatingHost = clientResponse.getConnection().getHost();
                        String location = rebuildLocation(Util.urlDecode(locations[i]), request.getHost(), originatingHost);
                        response.addField("Location", location);
                        if (log.isDebugEnabled())
                            log.debug("Location is now '" + location + "'");
                    }
          break;
        case 304: // Not Modified
          // Do nothing return as is
          break;
        case 305: // Use proxy
          log.warn("Detected HTTP response 305 [Use proxy] this may break reverse proxy!");
          break;
        default:
          log.error("Got unknown 3XX response code from server " + clientResponse.getStatus());
      }
    }
  }
   
    static final String rebuildLocation(String location, String host, String originatingHost) {
        // Check against the requests Host value and change the Location if required
        if (location.startsWith("http://" + host)) {
            String protocolStripped = stripProtocol(location);
            return encodeURL("https://" + protocolStripped);
        } else if (location.startsWith("http://" + originatingHost) || location.startsWith("https://" + originatingHost)) {
            String protocolStripped = stripProtocol(location);
            int indexOf = protocolStripped.indexOf('/');
            if (indexOf == -1) {
                return encodeURL("https://" + host);
            } else {
                String remainingPath = protocolStripped.substring(indexOf);
                return encodeURL("https://" + host + remainingPath);
            }
        } else {
            if (log.isDebugEnabled()) {
                log.debug("Redirect location may result in reverse proxy error " + location);
            }
        }
        return encodeURL(location);
    }
   
    static final String stripProtocol(String url) {
        if(url.startsWith("http://")) {
            return url.substring(7);
        } else if(url.startsWith("https://")) {
            return url.substring(8);
        }
        return url;
    }
   
    void addCustomHeaders(ReverseProxyWebForward webForward, ProxiedHttpMethod method) {

    /**
     * Add any custom headers to the request
     */
    Map customHeaders = webForward.getCustomHeaders();
    String header;
    for (Iterator it = customHeaders.entrySet().iterator(); it.hasNext();) {
      Map.Entry entry = (Map.Entry) it.next();
      header = (String) entry.getKey();
      Vector v = (Vector) entry.getValue();
      for (Iterator it2 = v.iterator(); it2.hasNext();) {
        method.getProxiedRequest().addHeaderField(header, (String) it2.next());
      }
    }
  }

  void checkInsecureIIS(ReverseProxyWebForward webForward, HttpResponse clientResponse) {

    /**
     * Perform a check to see if we're connected to an IIS server and if the
     * backend server is insecure. If it is set the customer
     * Front-End-Https: on header.
     */
    String server = clientResponse.getHeaderField("Server");

    if (server != null && server.startsWith("Microsoft-IIS")) {
      if (!webForward.containsCustomHeader("Front-End-Https"))
        webForward.setCustomHeader("Front-End-Https", "on");
    }
  }

  void filterUnsupportedAuthMethods(HttpResponse clientResponse) {

    /**
     * Filter out unsupported authentication methods because they dont work
     * through the reverse proxy - the best way to enable these will be to
     * allow credentials to be set on the reverse proxy web forward.
     */
    String[] challenges = clientResponse.getHeaderFields("www-authenticate");

    if (challenges != null) {
      clientResponse.removeFields("www-authenticate");

      for (int i = 0; i < challenges.length; i++) {
        if (challenges[i].toLowerCase().startsWith("basic") || challenges[i].toLowerCase().startsWith("digest")
          || challenges[i].toLowerCase().startsWith("ntlm")) {
          clientResponse.setHeaderField("WWW-Authenticate", challenges[i]);
        }
      }
    }
  }

  ProxiedHttpMethod getMethod(HttpClient client, LaunchSession launchSession, RequestHandlerRequest request, URL target) {

    ReverseProxyWebForward webForward = (ReverseProxyWebForward) launchSession.getResource();
    ProxiedHttpMethod method;

    VariableReplacement v = new VariableReplacement();
    v.setRequest(request);
    v.setSession(launchSession.getSession());
    v.setPolicy(launchSession.getPolicy());
   
    /**
     * POST parameters are now not being
     */

    if (!webForward.getFormType().equals(WebForwardTypes.FORM_SUBMIT_NONE)
        && !webForward.getFormType().equals(WebForwardTypes.FORM_SUBMIT_NONE)
        && !webForward.getFormType().equals("")
        && !webForward.getFormType().equals(WebForwardTypes.FORM_SUBMIT_JAVASCRIPT)
        && !Boolean.TRUE.equals(launchSession.getAttribute(LAUNCH_ATTR_AUTH_POSTED))) {

      /**
       * This code will automatically submit form parameters. If it is a post,
       * then we ignore the parameters request and use the webforward target.
       */
      method = new ProxiedHttpMethod(webForward.getFormType(),
              target.getFile(),
              webForward.getFormType().equals(WebForwardTypes.FORM_SUBMIT_POST) new MultiMap() : new MultiMap(request.getParameters()),
              launchSession.getSession(),
              webForward.getFormType().equals(WebForwardTypes.FORM_SUBMIT_POST));

      if (webForward.getCharset() != null
          && !webForward.getCharset().equals("")
          && !webForward.getCharset().equals(WebForwardTypes.DEFAULT_ENCODING))
        method.setCharsetEncoding(webForward.getCharset());

      StringTokenizer tokens = new StringTokenizer(webForward.getFormParameters(), "\n");
      int idx;
      String param;
     
      while (tokens.hasMoreTokens()) {
        param = v.replace(tokens.nextToken().trim());
        idx = param.indexOf('=');
        if (idx > -1) {
          method.addParameter(param.substring(0, idx), param.substring(idx + 1));
        } else
          method.addParameter(param, "");
      }
     
      launchSession.setAttribute(LAUNCH_ATTR_AUTH_POSTED, Boolean.TRUE);
      processRequestHeaders(request, method);
     
      // Do not send through any cookies on the authentication request
      method.getProxiedRequest().removeFields(HttpConstants.HDR_COOKIE);
      client.removeAllCookies();

    } else {
      method = new ProxiedHttpMethod(request.getMethod(),
              request.getURIEncoded(),
              new MultiMap(request.getParameters()),
              launchSession.getSession(),
              request.getContentType() != null && request.getContentType()
                      .toLowerCase()
                      .startsWith("application/x-www-form-urlencoded"));
      if (webForward.getCharset() != null
          && !webForward.getCharset().equals("")
          && !webForward.getCharset().equals(WebForwardTypes.DEFAULT_ENCODING))
        method.setCharsetEncoding(webForward.getCharset());
      processRequestHeaders(request, method);
    }

    return method;
  }

  HttpClient getClient(LaunchSession launchSession, URL target) {

    ReverseProxyWebForward webForward = (ReverseProxyWebForward) launchSession.getResource();

    String hostname = target.getHost();
    boolean isSecure = target.getProtocol().equalsIgnoreCase("https");
    int connectPort = target.getPort() == -1 ? (isSecure ? 443 : 80) : target.getPort();

    HttpClient client;

    SessionClients clients = null;
    // CookieMap cookieMap = null;
    synchronized (launchSession.getSession().getHttpSession()) {
      clients = (SessionClients) launchSession.getSession().getHttpSession().getAttribute(Constants.HTTP_CLIENTS);
      if (clients == null) {
        clients = new SessionClients();
        launchSession.getSession().getHttpSession().setAttribute(Constants.HTTP_CLIENTS, clients);
      }
    }

    synchronized (clients) {
      String key = hostname + ":"
        + connectPort
        + ":"
        + isSecure
        + ":"
        + webForward.getResourceId()
        + ":"
        + Thread.currentThread().getName()
        + ":"
        + launchSession.getSession().getId();
      client = (HttpClient) clients.get(key);

      if (client == null) {
        client = new HttpClient(hostname, connectPort, isSecure);
        client.setIncludeCookies(false);
       
        if (!webForward.getPreferredAuthenticationScheme().equals(HttpAuthenticatorFactory.NONE) && !webForward.getAuthenticationUsername()
                .equals("")
          && !webForward.getAuthenticationPassword().equals("")) {
          PasswordCredentials pwd = new PasswordCredentials();
          pwd.setUsername(SessionInfoReplacer.replace(launchSession.getSession(), webForward.getAuthenticationUsername()));
          pwd.setPassword(SessionInfoReplacer.replace(launchSession.getSession(), webForward.getAuthenticationPassword()));
          client.setCredentials(pwd);
        }

        // Set the preferred scheme
        client.setPreferredAuthentication(webForward.getPreferredAuthenticationScheme());

        // If we're using basic authentication then preempt the 401
        // response
        client.setPreemtiveAuthentication(webForward.getPreferredAuthenticationScheme().equalsIgnoreCase("BASIC"));

        clients.put(key, client);
      }
    }

    return client;
  }

  void setRequestEncoding(LaunchSession launchSession, URL target, RequestHandlerRequest request) {

    ReverseProxyWebForward webForward = (ReverseProxyWebForward) launchSession.getResource();

    /**
     * This code sets the character encoding of the request. This may be
     * overridden because some servers assume the character set and there is
     * no way for us work this.
     */
    try {
      if (webForward.getCharset() != null
          && !webForward.getCharset().equals("")
          && !webForward.getCharset().equals(WebForwardTypes.DEFAULT_ENCODING))
        request.setCharacterEncoding(webForward.getCharset());
    } catch (UnsupportedEncodingException ex) {
      log.error("Java runtime does not support encoding", ex);
    }
  }

  SessionInfo locateSession(String pathInContext, String pathParams, RequestHandlerRequest request,
                RequestHandlerResponse response) {
    /*
     * When not authenticated, dont reverse proxy anything. We use the logon
     * ticket to get the HttpSession in use
     */
    SessionInfo session = null;

    /**
     * The launching of a reverse proxy will always be a GET. This change
     * will allow us to set the character encoding of the request later so
     * that POST parameters are not incorrectly encoded.
     */
    if (request.getMethod().equals("GET") && request.getParameters().containsKey(LaunchSession.LONG_LAUNCH_ID)) {
      String launchId = (String) request.getParameters().get(LaunchSession.LONG_LAUNCH_ID);

      // Get the actual session for the reverse proxy
      LaunchSession launchSession = LaunchSessionFactory.getInstance().getLaunchSession(launchId);
      if (launchSession != null) {

        // If the launch session is not for a reverse proxy web forward
        // then ignore
        if (launchSession.isTracked() && launchSession.getResource() instanceof ReverseProxyWebForward) {
          session = launchSession.getSession();

          Cookie[] cookies = request.getCookies();
          if (cookies != null) {
            for (int i = 0; i < cookies.length; i++) {
              if (cookies[i].getName().equalsIgnoreCase(sessionCookie)) {
                LogonControllerFactory.getInstance().attachSession(cookies[i].getValue(), session);
                break;
              }
            }
          }

          LogonControllerFactory.getInstance().addCookies(request, response, session.getLogonTicket(), session);
        }
      }

    } else {
      Cookie[] cookies = request.getCookies();

      if (cookies != null) {
        for (int i = 0; i < cookies.length; i++) {
          if (cookies[i].getName().equalsIgnoreCase(sessionCookie)) {
            session = LogonControllerFactory.getInstance().getSessionInfoBySessionId(cookies[i].getValue());
            if (session != null) {
              LogonControllerFactory.getInstance().addCookies(request, response, session.getLogonTicket(), session);
              session.access();
              break;
            }
          }
          if (cookies[i].getName().equalsIgnoreCase(Constants.DOMAIN_LOGON_TICKET) || cookies[i].getName()
                  .equalsIgnoreCase(Constants.LOGON_TICKET)) {
            session = LogonControllerFactory.getInstance().getSessionInfo(cookies[i].getValue());
            if (session != null) {
              LogonControllerFactory.getInstance().addCookies(request, response, session.getLogonTicket(), session);
              session.access();
              break;
            }
          }

        }
      }
    }

    if (session != null) {
      session.access();
    }

    return session;
  }
 
  /**
   * Takes an unencoded URL query string, and encodes it.
   * @param query
   * @return
   */
  public static final String encodeQuery(String query) {
    String encoded = "";
    StringTokenizer pairs = new StringTokenizer(query, "&");
    while(pairs.hasMoreTokens()) {
      StringTokenizer pair = new StringTokenizer(pairs.nextToken(), "=");
      if(pair.hasMoreTokens()) {
        encoded += (encoded.length()==0 ? "" : "&") + URLUTF8Encoder.encode(pair.nextToken(), true);
        if(pair.hasMoreTokens()) {
          encoded += "=" + URLUTF8Encoder.encode(pair.nextToken(), true);
        }
       
      }
    }
    return encoded;
  }

  /**
   * Encodes a URL
   * @param location
   * @return
   */
  public static final String encodeURL(String location) {
   
    try {
      URL url = new URL(location);
     
      StringBuffer buf = new StringBuffer();
      buf.append(url.getProtocol());
      buf.append("://");
            if(!Util.isNullOrTrimmedBlank(url.getUserInfo())) {
                buf.append(DAVUtilities.encodeURIUserInfo(url.getUserInfo()));
                buf.append("@");
            }
      buf.append(url.getHost());
      if(url.getPort() != -1) {
          buf.append(":");
          buf.append(url.getPort());
      }
            if(!Util.isNullOrTrimmedBlank(url.getPath())) {
                buf.append(URLUTF8Encoder.encode(url.getPath(), false));
            }
      if(!Util.isNullOrTrimmedBlank(url.getQuery())) {
          buf.append("?");
          buf.append(encodeQuery(url.getQuery()));
      }
     
      return buf.toString();
    } catch (MalformedURLException e) {
     
      int idx = location.indexOf('?');
      if(idx > -1 && idx < location.length()-1) {
        return URLUTF8Encoder.encode(location.substring(0, idx), false) + "?" + encodeQuery(location.substring(idx+1));
      } else
        return URLUTF8Encoder.encode(location, false);
    }
  }

}
TOP

Related Classes of com.adito.reverseproxy.ReverseProxyMethodHandler

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.