Java tutorial
/* * 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.replacementproxy; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.io.PrintWriter; import java.net.MalformedURLException; import java.net.URL; import java.util.Enumeration; import java.util.Iterator; import java.util.List; import java.util.StringTokenizer; import javax.servlet.http.HttpSession; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import com.maverick.http.HttpAuthenticatorFactory; import com.maverick.http.HttpClient; import com.maverick.http.HttpResponse; import com.maverick.http.PasswordCredentials; import com.maverick.util.IOUtil; import com.adito.boot.Branding; import com.adito.boot.CaseInsensitiveMap; import com.adito.boot.HttpConstants; import com.adito.boot.SystemProperties; import com.adito.boot.Util; import com.adito.core.CookieItem; import com.adito.core.CookieMap; import com.adito.core.MultiMap; import com.adito.core.RequestParameterMap; import com.adito.core.RequestParameterMap.ProxyURIDetails; import com.adito.core.stringreplacement.SessionInfoReplacer; import com.adito.policyframework.LaunchSession; import com.adito.reverseproxy.SessionClients; import com.adito.security.Constants; import com.adito.util.ProxiedHttpMethod; import com.adito.webforwards.WebForwardDatabaseFactory; import com.adito.webforwards.WebForwardTypes; /** */ public class ProxiedRequestDispatcher { final static Log log = LogFactory.getLog(ProxiedRequestDispatcher.class); static CaseInsensitiveMap ignoreHeaders = new CaseInsensitiveMap(); final static String sessionIdCookieName = SystemProperties.get("adito.cookie", "JSESSIONID"); /** * Launch session attribute for storing whether authentication has been * posted yet */ public static final String LAUNCH_ATTR_AUTH_POSTED = "authPosted"; static { ignoreHeaders.put(HttpConstants.HDR_PROXY_CONNECTION, Boolean.TRUE); ignoreHeaders.put(HttpConstants.HDR_ACCEPT_ENCODING, Boolean.TRUE); ignoreHeaders.put(HttpConstants.HDR_TRANSFER_ENCODING, Boolean.TRUE); ignoreHeaders.put(HttpConstants.HDR_TE, Boolean.TRUE); ignoreHeaders.put(HttpConstants.HDR_TRAILER, Boolean.TRUE); ignoreHeaders.put(HttpConstants.HDR_PROXY_AUTHORIZATION, Boolean.TRUE); ignoreHeaders.put(HttpConstants.HDR_PROXY_AUTHENTICATE, Boolean.TRUE); ignoreHeaders.put(HttpConstants.HDR_UPGRADE, Boolean.TRUE); } private RequestProcessor requestProcessor; private LaunchSession launchSession; private HttpResponse serverResponse; private int responseCode; private String responseMessage; private CookieMap cookieMap; public ProxiedRequestDispatcher(RequestProcessor requestProcessor, LaunchSession launchSession, CookieMap cookieMap) { this.launchSession = launchSession; this.requestProcessor = requestProcessor; this.cookieMap = cookieMap; } /** * Send the request to the target server. * * @return request successful * @throws Exception on any error */ public boolean sendProxiedRequest() throws Exception { byte[] content = null; OutputStream serverOut = null; HttpClient client; SessionClients clients = null; HttpSession session = requestProcessor.getSession(); // Manage the sessions clients synchronized (session) { clients = (SessionClients) session.getAttribute(Constants.HTTP_CLIENTS); if (clients == null) { clients = new SessionClients(); session.setAttribute(Constants.HTTP_CLIENTS, clients); } } RequestParameterMap requestParameters = requestProcessor.getRequestParameters(); URL proxiedURL = requestParameters.getProxiedURIDetails().getProxiedURL(); synchronized (clients) { String key = proxiedURL.getHost() + ":" + (proxiedURL.getPort() > 0 ? proxiedURL.getPort() : proxiedURL.getProtocol().equals("https") ? 443 : 80) + ":" + proxiedURL.getProtocol().equals("https") + ":" + requestProcessor.getWebForward().getResourceId() + Thread.currentThread().getName(); client = (HttpClient) clients.get(key); if (client == null) { client = new HttpClient(proxiedURL.getHost(), (proxiedURL.getPort() > 0 ? proxiedURL.getPort() : proxiedURL.getProtocol().equals("https") ? 443 : 80), proxiedURL.getProtocol().equals("https")); if (!requestProcessor.getWebForward().getPreferredAuthenticationScheme() .equals(HttpAuthenticatorFactory.NONE) && !requestProcessor.getWebForward().getAuthenticationUsername().equals("") && !requestProcessor.getWebForward().getAuthenticationPassword().equals("")) { PasswordCredentials pwd = new PasswordCredentials(); pwd.setUsername(SessionInfoReplacer.replace(requestProcessor.getSessionInfo(), requestProcessor.getWebForward().getAuthenticationUsername())); pwd.setPassword(SessionInfoReplacer.replace(requestProcessor.getSessionInfo(), requestProcessor.getWebForward().getAuthenticationPassword())); client.setCredentials(pwd); } // Set the preferred scheme client.setPreferredAuthentication( requestProcessor.getWebForward().getPreferredAuthenticationScheme()); // Do not track cookies, browser will instead client.setIncludeCookies(false); // If we're using basic authentication then preempt the 401 // response client.setPreemtiveAuthentication(requestProcessor.getWebForward() .getPreferredAuthenticationScheme().equalsIgnoreCase("BASIC")); clients.put(key, client); } } if (log.isDebugEnabled()) log.debug("Connecting to [" + proxiedURL + "] "); ProxiedHttpMethod method; if (!requestProcessor.getWebForward().getFormType().equals(WebForwardTypes.FORM_SUBMIT_NONE) && !requestProcessor.getWebForward().getFormType().equals("") && !requestProcessor.getWebForward().getFormType().equals(WebForwardTypes.FORM_SUBMIT_JAVASCRIPT) && !Boolean.TRUE.equals(launchSession.getAttribute(LAUNCH_ATTR_AUTH_POSTED))) { /** * This code will automatically submit form parameters. * * LDP - Use the full URI with parameters as we need to ensure parameters are sent as they are received. */ method = new ProxiedHttpMethod(requestProcessor.getWebForward().getFormType(), SessionInfoReplacer.replace(requestProcessor.getSessionInfo(), requestProcessor.getUriEncoded()), requestProcessor.getWebForward().getFormType().equals(WebForwardTypes.FORM_SUBMIT_POST) ? new MultiMap() : requestParameters, requestProcessor.getSessionInfo(), requestProcessor.getWebForward().getFormType().equals(WebForwardTypes.FORM_SUBMIT_POST)); if (requestProcessor.getWebForward().getEncoding() != null && !requestProcessor.getWebForward().getEncoding().equals(WebForwardTypes.DEFAULT_ENCODING)) method.setCharsetEncoding(requestProcessor.getWebForward().getEncoding()); StringTokenizer tokens = new StringTokenizer(requestProcessor.getWebForward().getFormParameters(), "\n"); int idx; String param; while (tokens.hasMoreTokens()) { param = SessionInfoReplacer.replace(requestProcessor.getLaunchSession().getSession(), tokens.nextToken().trim()); idx = param.indexOf('='); if (idx > -1 && idx < param.length() - 1) { method.addParameter(param.substring(0, idx), param.substring(idx + 1)); } else method.addParameter(param, ""); } launchSession.setAttribute(LAUNCH_ATTR_AUTH_POSTED, Boolean.TRUE); } else { /** * LDP - Use the full URI with parameters as we need to ensure parameters are sent as they are received. */ method = new ProxiedHttpMethod(requestProcessor.getMethod(), SessionInfoReplacer.replace(requestProcessor.getSessionInfo(), requestProcessor.getUriEncoded()), requestParameters, requestProcessor.getSessionInfo(), requestProcessor.getRequest().getContentType() != null && requestProcessor.getRequest() .getContentType().startsWith("application/x-www-form-urlencoded")); if (requestProcessor.getWebForward().getEncoding() != null && !requestProcessor.getWebForward().getEncoding().equals(WebForwardTypes.DEFAULT_ENCODING)) method.setCharsetEncoding(requestProcessor.getWebForward().getEncoding()); } int contentLength = 0; String contentType = null; for (Enumeration e = requestProcessor.getHeaderNames(); e.hasMoreElements();) { String hdr = (String) e.nextElement(); if (ignoreHeaders.containsKey(hdr)) { if (log.isDebugEnabled()) log.debug("Ignoring " + hdr + " = " + requestProcessor.getHeader(hdr)); continue; } // See if there any replacements for this header List replacements = WebForwardDatabaseFactory.getInstance().getReplacementsForContent( launchSession.getSession().getUser().getPrincipalName(), Replacement.REPLACEMENT_TYPE_SENT_HEADER, hdr, proxiedURL.toExternalForm()); Enumeration vals = requestProcessor.getHeaders(hdr); while (vals.hasMoreElements()) { String val = (String) vals.nextElement(); // Do the replacements for (Iterator i = replacements.iterator(); i.hasNext();) { Replacement r = (Replacement) i.next(); val = val.replaceAll(r.getMatchPattern(), r.getReplacePattern()); } if (val != null) { if (hdr.equalsIgnoreCase(HttpConstants.HDR_HOST)) { if (proxiedURL.getPort() == -1) { val = proxiedURL.getHost(); } else { val = proxiedURL.getHost() + ":" + proxiedURL.getPort(); } } else if (hdr.equalsIgnoreCase(HttpConstants.HDR_COOKIE)) { // We shouldnt supply our local cookies if (log.isDebugEnabled()) log.debug(" Splitting cookie " + val); String[] cookieVals = val.split("\\;"); StringBuffer newVal = new StringBuffer(); for (int i = 0; i < cookieVals.length; i++) { if (log.isDebugEnabled()) log.debug("Cookie = " + cookieVals[i]); int idx = cookieVals[i].indexOf('='); String cn = ""; String cv = ""; if (idx == -1) { cn = Util.trimBoth(cookieVals[i]); } else if (idx < cookieVals[i].length() - 1) { cn = Util.trimBoth(cookieVals[i].substring(0, idx)); cv = Util.trimBoth(cookieVals[i].substring(idx + 1)); } else { cn = Util.trimBoth(cookieVals[i].substring(0, idx)); } if (cn.equals("webForward") || cn.equals(Constants.LOGON_TICKET) || cn.equals(Constants.DOMAIN_LOGON_TICKET) || (cn.equals(sessionIdCookieName) && cv.equals(requestProcessor.getSession().getId()))) { if (log.isDebugEnabled()) log.debug(" Omiting cookie " + cn + "=" + cv); } else { // TODO is it ok to store the cookie map in // memory? CookieItem cookie = cookieMap.getByFakeCookieName(cn); if (cookie == null) { if (log.isDebugEnabled()) log.debug(" Cookie " + cn + " unmapped, ignoring"); // Un-mapped cookie, ignore } else { if (log.isDebugEnabled()) log.debug(" Including cookie " + cn + "=" + cv); if (newVal.length() > 0) { newVal.append("; "); } newVal.append(cookie.getRealCookieName()); newVal.append("="); newVal.append(Util.urlDecode(cv)); } } } if (newVal.length() == 0) { if (log.isDebugEnabled()) log.debug("Send no cookies"); val = null; } else { val = newVal.toString(); if (log.isDebugEnabled()) log.debug("Using cooking val of " + val); } } // Change the refererer else if (hdr.equalsIgnoreCase(HttpConstants.HDR_REFERER)) { try { URL refUrl = new URL(val); refUrl.getQuery(); if (log.isDebugEnabled()) log.debug("Splitting refererer query string [" + val + "] " + refUrl.getQuery()); if (refUrl.getFile() != null) { ProxyURIDetails uriDetails = RequestParameterMap.parseProxyPath(refUrl.getFile(), "UTF-8"); if (uriDetails.getProxiedURL() == null) { /* If the referer is not a proxied URL then don't send a referer. This * way a target server won't know its a request from Adito by * examining the referer */ val = null; } else { val = uriDetails.getProxiedURL().toExternalForm(); } } } catch (MalformedURLException murle) { } } else if (hdr.equalsIgnoreCase(HttpConstants.HDR_CONTENT_LENGTH)) { contentLength = Integer.parseInt(val); continue; } else if (hdr.equalsIgnoreCase(HttpConstants.HDR_CONTENT_TYPE)) { contentType = val; continue; } else if (hdr.equalsIgnoreCase(HttpConstants.HDR_CONNECTION)) { // Handled by the Maverick HTTP client continue; } if (val != null) { method.getProxiedRequest().addHeaderField(hdr, val); } if (log.isDebugEnabled()) log.debug("Adding request property " + hdr + " = " + val); } } } // Proxy headers method.getProxiedRequest().setHeaderField("Via", Branding.PRODUCT_NAME); if (requestParameters.isMultipart() && requestParameters.getMultipartDataLength() > 0) { method.setContent(getDebugStream(requestParameters.getMultipartData()), requestParameters.getMultipartDataLength(), requestParameters.getOriginalContentType()); } else if (!requestParameters.isWwwFormURLEncoded() && contentLength > 0) { method.setContent(getDebugStream(requestProcessor.getRequest().getInputStream()), requestParameters.getOriginalContentLength(), requestParameters.getOriginalContentType()); } serverResponse = client.execute(method); responseCode = serverResponse.getStatus(); responseMessage = serverResponse.getReason(); return true; } InputStream getDebugStream(InputStream in) throws IOException { if (log.isDebugEnabled()) { ByteArrayOutputStream baos = new ByteArrayOutputStream(); IOUtil.copy(in, baos); byte[] buf = baos.toByteArray(); log.debug("Sending content :-\n" + new String(buf)); return new ByteArrayInputStream(buf); } return in; } public int getResponseCode() { return responseCode; } public HttpResponse getServerResponse() { return serverResponse; } public String getResponseMessage() { return responseMessage; } }