KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > sslexplorer > reverseproxy > ReverseProxyMethodHandler


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

19             
20 package com.sslexplorer.reverseproxy;
21
22 import java.io.ByteArrayOutputStream JavaDoc;
23 import java.io.EOFException JavaDoc;
24 import java.io.IOException JavaDoc;
25 import java.io.UnsupportedEncodingException JavaDoc;
26 import java.net.MalformedURLException JavaDoc;
27 import java.net.URL JavaDoc;
28 import java.net.UnknownHostException JavaDoc;
29 import java.util.Enumeration JavaDoc;
30 import java.util.HashSet JavaDoc;
31 import java.util.Iterator JavaDoc;
32 import java.util.Map JavaDoc;
33 import java.util.StringTokenizer JavaDoc;
34 import java.util.Vector JavaDoc;
35
36 import javax.servlet.http.Cookie JavaDoc;
37
38 import org.apache.commons.logging.Log;
39 import org.apache.commons.logging.LogFactory;
40 import org.mortbay.util.MultiMap;
41
42 import com.maverick.http.AuthenticationCancelledException;
43 import com.maverick.http.HttpAuthenticatorFactory;
44 import com.maverick.http.HttpClient;
45 import com.maverick.http.HttpException;
46 import com.maverick.http.HttpResponse;
47 import com.maverick.http.PasswordCredentials;
48 import com.maverick.http.UnsupportedAuthenticationException;
49 import com.maverick.util.URLUTF8Encoder;
50 import com.sslexplorer.boot.ContextHolder;
51 import com.sslexplorer.boot.HttpConstants;
52 import com.sslexplorer.boot.RequestHandler;
53 import com.sslexplorer.boot.RequestHandlerException;
54 import com.sslexplorer.boot.RequestHandlerRequest;
55 import com.sslexplorer.boot.RequestHandlerResponse;
56 import com.sslexplorer.boot.Util;
57 import com.sslexplorer.core.CoreEvent;
58 import com.sslexplorer.core.CoreServlet;
59 import com.sslexplorer.core.stringreplacement.SessionInfoReplacer;
60 import com.sslexplorer.core.stringreplacement.VariableReplacement;
61 import com.sslexplorer.policyframework.LaunchSession;
62 import com.sslexplorer.policyframework.LaunchSessionFactory;
63 import com.sslexplorer.policyframework.ResourceAccessEvent;
64 import com.sslexplorer.security.Constants;
65 import com.sslexplorer.security.LogonControllerFactory;
66 import com.sslexplorer.security.SessionInfo;
67 import com.sslexplorer.util.ProxiedHttpMethod;
68 import com.sslexplorer.vfs.webdav.DAVUtilities;
69 import com.sslexplorer.webforwards.AbstractAuthenticatingWebForwardHandler;
70 import com.sslexplorer.webforwards.ReverseProxyWebForward;
71 import com.sslexplorer.webforwards.WebForwardEventConstants;
72 import com.sslexplorer.webforwards.WebForwardPlugin;
73 import com.sslexplorer.webforwards.WebForwardTypes;
74
75 /**
76  * Request handler that deals with both <i>Reverse Proxy</i> and <i>Replacement
77  * Proxy</i> web forwards.
78  *
79  * @author Brett Smith <a HREF="mailto: brett@3sp.com">&lt;brett@3sp.com&gt;</a>
80  */

81 public class ReverseProxyMethodHandler extends AbstractAuthenticatingWebForwardHandler implements RequestHandler {
82
83     /**
84      * Launch session attribute for storing whether authentication has been
85      * posted yet
86      */

87     public static final String JavaDoc LAUNCH_ATTR_AUTH_POSTED = "authPosted";
88
89     final static String JavaDoc sessionCookie = System.getProperty("sslexplorer.cookie", "JSESSIONID");
90
91     static HashSet JavaDoc<String JavaDoc> ignoredHeaders = new HashSet JavaDoc<String JavaDoc>();
92
93     static {
94         ignoredHeaders.add("Location".toUpperCase());
95         ignoredHeaders.add("Server".toUpperCase());
96         ignoredHeaders.add("Date".toUpperCase());
97     }
98
99     static Log log = LogFactory.getLog(ReverseProxyMethodHandler.class);
100
101     public boolean handle(String JavaDoc pathInContext, String JavaDoc pathParams, RequestHandlerRequest request, RequestHandlerResponse response)
102                     throws RequestHandlerException, IOException JavaDoc {
103         if (log.isDebugEnabled())
104             log.debug("Check if Reverse Proxy Request for: " + pathInContext);
105
106     
107         /*
108          * First try and locate the session, if there is no session then this is
109          * definitely not a reverse proxy request
110          */

111         LaunchSession launchSession = null;
112         SessionInfo session = locateSession(request, response);
113
114         if (session == null) {
115             // If we have no session, then this cannot be a reverse proxy
116
// request
117
if (log.isDebugEnabled())
118                 log.debug("No session, not a reverse proxy.");
119             return false;
120         }
121         
122         try {
123             // Perhaps this is a reverse proxy?
124
String JavaDoc host = request.getHost();
125             ReverseProxyWebForward wf = null;
126
127             // Active Proxy
128

129             if (host != null && !host.equals("") && host.indexOf('.') > -1) {
130                 int idx = host.indexOf('.');
131                 if (idx != -1) {
132                     try {
133                         String JavaDoc uniqueId = host.substring(0, idx);
134                         launchSession = LaunchSessionFactory.getInstance().getLaunchSession(session, uniqueId);
135                         if (launchSession != null) {
136                             wf = (ReverseProxyWebForward) launchSession.getResource();
137                             launchSession.checkAccessRights(null, session);
138                             if (!((ReverseProxyWebForward) wf).getActiveDNS()) {
139                                 throw new Exception JavaDoc("Appears to be an active DNS request but the associated web forward is not active DNS. Is someone trying something funny???");
140                             }
141                             return handleReverseProxy(pathInContext, pathParams, request, response, launchSession);
142                         }
143
144                     } catch (Exception JavaDoc ex) {
145                         if (log.isDebugEnabled())
146                             log.debug("Active DNS web forward lookup failed", ex);
147                     }
148                 } else {
149                     if (log.isDebugEnabled())
150                         log.debug("Not active DNS.");
151                 }
152             }
153
154             String JavaDoc hostHeader = request.getHost();
155             int idx = hostHeader.indexOf(':');
156             if (idx > -1)
157                 hostHeader = hostHeader.substring(0, idx);
158
159             /* Ordinary reverse proxy? There can only ever be one launch session per reverse proxy
160              * as there is no way of maintaining the session across requests. If a user launches the
161              * resource more than once, the old launch session will be removed
162              */

163
164             for (LaunchSession rs : LaunchSessionFactory.getInstance().getLaunchSessionsForType(session,
165                 WebForwardPlugin.WEBFORWARD_RESOURCE_TYPE)) {
166                 if (rs.getResource() instanceof ReverseProxyWebForward) {
167                     wf = (ReverseProxyWebForward) rs.getResource();
168                     if (wf.isValidPath(pathInContext) || (wf.getHostHeader() != null && wf.getHostHeader().equals(hostHeader))) {
169                         rs.checkAccessRights(null, session);
170                         return handleReverseProxy(pathInContext, pathParams, request, response, rs);
171                     }
172                 }
173             }
174         } catch (Exception JavaDoc e) {
175             log.error("Failed to process web forward.", e);
176             if (session != null) {
177                 session.getHttpSession().setAttribute(Constants.EXCEPTION, e);
178                 response.sendRedirect("/showPopupException.do");
179             } else {
180                 throw new RequestHandlerException("Failed to process web forward.", 500);
181             }
182             return true;
183         }
184         return false;
185     }
186
187     private boolean handleReverseProxy(String JavaDoc path, String JavaDoc params, RequestHandlerRequest request, RequestHandlerResponse response,
188                                         LaunchSession launchSession) throws IOException JavaDoc {
189
190         ReverseProxyWebForward webForward = (ReverseProxyWebForward) launchSession.getResource();
191         boolean connectionError = true;
192         
193         /* Because we are in a request handler, the session's last access time
194          * does not get updated by the container
195          */

196         launchSession.getSession().access();
197
198         /***
199          * LDP - DO NOT use request parameter map until the encoding has been set. If you
200          * call getParameters it decodes the parameters so this can only be done once the
201          * character set has been set.
202          */

203
204         try {
205             URL JavaDoc target = getTarget(launchSession, request);
206             setRequestEncoding(launchSession, target, request);
207             HttpClient client = getClient(launchSession, target);
208             ProxiedHttpMethod method = getMethod(client, launchSession, request, target);
209             processPortsAndXForwarding(method, request);
210             checkProcessedContent(launchSession, method, request);
211             addCustomHeaders(webForward, method);
212             com.maverick.http.HttpResponse clientResponse = doExecute(client, method);
213             connectionError = false;
214             checkInsecureIIS(webForward, clientResponse);
215             filterUnsupportedAuthMethods(clientResponse);
216             processStatus(clientResponse, response);
217             processRedirects(clientResponse, request, response);
218             processHeaders(clientResponse, response);
219
220             /*
221              * If the content type is HTML, this webforwad is configured for
222              * automatic JavaScript authentication and authentication has not
223              * yet been performed, then tack the JavaScript on to the end of the
224              * content. This requires that the content is read into memory and
225              * the content length adjusted
226              */

227             if (clientResponse.getStatus() == 200 && webForward.getFormType().equals(WebForwardTypes.FORM_SUBMIT_JAVASCRIPT)
228                 && "text/html".equals(clientResponse.getContentTypeWithoutParameter())
229                 && !Boolean.TRUE.equals(launchSession.getAttribute(LAUNCH_ATTR_AUTH_POSTED))) {
230                 ByteArrayOutputStream JavaDoc baos = new ByteArrayOutputStream JavaDoc();
231                 Util.copy(clientResponse.getInputStream(), baos, -1, 16384);
232                 addJavaScriptAuthenticationCode(launchSession, baos, 0);
233                 byte[] arr = baos.toByteArray();
234                 if (clientResponse.getHeaderField("Content-Length") != null) {
235                     response.setField("Content-Length", String.valueOf(arr.length));
236                 }
237                 response.getOutputStream().write(arr);
238                 launchSession.setAttribute(LAUNCH_ATTR_AUTH_POSTED, Boolean.TRUE);
239             } else {
240                 Util.copy(clientResponse.getInputStream(), response.getOutputStream(), -1, 16384);
241             }
242             
243             clientResponse.close();
244
245             return true;
246         } catch (UnsupportedAuthenticationException ex) {
247             log.error("?", ex);
248         } catch (com.maverick.http.HttpException ex) {
249             log.error("?", ex);
250         } catch (EOFException JavaDoc e) {
251             /*
252              * This is probably just because the user clicked on a link before
253              * the page had finished downloading.
254              */

255             if (log.isDebugEnabled())
256                 log.debug("Received EOF in reverse proxy request [THIS IS PROBABLY NOT FATAL]", e);
257         } catch (IOException JavaDoc ex) {
258             if (connectionError) {
259                 response.sendError(404,
260                     "The proxied web server could not be contacted or did not respond correctly to the request! " + ex.getMessage());
261             }
262             log.error("?", ex);
263         } catch (AuthenticationCancelledException ex) {
264             log.error("?", ex);
265         }
266         return true;
267
268     }
269
270     HttpResponse doExecute(HttpClient client, ProxiedHttpMethod method) throws UnknownHostException JavaDoc, IOException JavaDoc,
271                     HttpException, UnsupportedAuthenticationException, AuthenticationCancelledException {
272         if (log.isDebugEnabled()) {
273             log.debug("Connecting to " + client.getHost() + ":" + client.getPort() + " (Secure = " + client.isSecure() + ")");
274         }
275         return client.execute(method);
276     }
277
278     URL JavaDoc getTarget(LaunchSession launchSession, RequestHandlerRequest request) throws MalformedURLException JavaDoc {
279         ReverseProxyWebForward webForward = (ReverseProxyWebForward) launchSession.getResource();
280         VariableReplacement r = new VariableReplacement();
281         r.setRequest(request);
282         r.setSession(launchSession.getSession());
283         r.setPolicy(launchSession.getPolicy());
284
285         URL JavaDoc target = new URL JavaDoc(r.replace(webForward.getDestinationURL()));
286
287         if (log.isDebugEnabled()) {
288             log.debug("Reverse proxy target " + target.toExternalForm());
289         }
290         return target;
291     }
292
293     void checkProcessedContent(LaunchSession launchSession, ProxiedHttpMethod method, RequestHandlerRequest request)
294                     throws IOException JavaDoc {
295         String JavaDoc contentType = request.getContentType();
296         int contentLength = request.getContentLength();
297
298         boolean hasProcessedContent = contentType != null && request.getMethod().equals("POST")
299             && contentType.equals("application/x-www-form-urlencoded");
300
301         if (contentLength > 0 && !hasProcessedContent) {
302             if(log.isDebugEnabled())
303                 log.debug("Setting request content of " + contentLength + " bytes with content type " + contentType + " available=" + request.getInputStream().available());
304             method.setContent(request.getInputStream(), contentLength, contentType);
305         }
306
307     }
308
309     private void processRequestHeaders(RequestHandlerRequest request, ProxiedHttpMethod method) {
310         String JavaDoc header;
311
312         for (Enumeration JavaDoc e = request.getFieldNames(); e.hasMoreElements();) {
313             header = (String JavaDoc) e.nextElement();
314
315             // Skip the connection header as our client maintains its own
316
// connections
317
if (header.equalsIgnoreCase(HttpConstants.HDR_CONNECTION) || header.equalsIgnoreCase(HttpConstants.HDR_KEEP_ALIVE)) {
318                 continue;
319             }
320
321             for (Enumeration JavaDoc j = request.getFieldValues(header); j.hasMoreElements();) {
322                 String JavaDoc val = (String JavaDoc) j.nextElement();
323                 if (header.equalsIgnoreCase("cookie")) {
324                     String JavaDoc[] cookieVals = val.split("\\;");
325                     StringBuffer JavaDoc newVal = new StringBuffer JavaDoc();
326                     for (int i = 0; i < cookieVals.length; i++) {
327                         if (log.isDebugEnabled())
328                             log.debug("Cookie = " + cookieVals[i]);
329                         
330                         // Its possible cookies may be sent without values
331
int idx = cookieVals[i].indexOf('=');
332                         String JavaDoc cn = idx == -1 ? cookieVals[i] : Util.trimBoth(cookieVals[i].substring(0, idx));
333                         String JavaDoc cv = idx == -1 ? null : Util.trimBoth(cookieVals[i].substring(idx + 1));
334                         
335                         // Ignore SSL-Exploer cookies
336
if (cn.equals(Constants.LOGON_TICKET) || cn.equals(Constants.DOMAIN_LOGON_TICKET)
337                             || cn.equals(System.getProperty("sslexplorer.cookie", "SSLX_SSESHID"))) {
338                             if (log.isDebugEnabled())
339                                 log.debug(" Omiting cookie " + cn + "=" + cv);
340                         } else {
341                             if (newVal.length() > 0) {
342                                 newVal.append("; ");
343                             }
344                             newVal.append(cn);
345                             if(cv != null) {
346                                 newVal.append("=");
347                                 newVal.append(cv);
348                             }
349                         }
350                     }
351                     if (newVal.length() > 0) {
352                         method.getProxiedRequest().addHeaderField(header, newVal.toString());
353                         if (log.isDebugEnabled())
354                             log.debug("HEADER: " + header + " " + val);
355                     }
356                 } else {
357                     method.getProxiedRequest().addHeaderField(header, val);
358                     if (log.isDebugEnabled())
359                         log.debug("HEADER: " + header + " " + val);
360                 }
361             }
362         }
363
364     }
365
366     void processPortsAndXForwarding(ProxiedHttpMethod method, RequestHandlerRequest request) {
367
368         String JavaDoc thisHost = ContextHolder.getContext().getHostname();
369         int thisPort = ContextHolder.getContext().getPort();
370
371         // Check for a non default port (we dont care if we receive on 443
372
// but
373
// forward to 80 as this would not change the host header
374
if (thisPort != 443 && thisPort != 80) {
375             thisHost += ":" + thisPort;
376         }
377
378         method.getProxiedRequest().setHeaderField("X-Forwarded-Host", thisHost);
379         method.getProxiedRequest().setHeaderField("X-Forwarded-For", request.getRemoteHost());
380         method.getProxiedRequest().setHeaderField("X-Forwarded-Server", thisHost);
381         method.getProxiedRequest().setHeaderField("X-Forwarded-Port", String.valueOf(thisPort));
382
383     }
384
385     void processStatus(HttpResponse clientResponse, RequestHandlerResponse response) {
386
387         if (log.isDebugEnabled())
388             log.debug("HTTP response is " + clientResponse.getStartLine());
389
390         response.setStatus(clientResponse.getStatus());
391         response.setReason(clientResponse.getReason());
392
393     }
394
395     void processHeaders(HttpResponse clientResponse, RequestHandlerResponse response) {
396
397         String JavaDoc header;
398         for (Enumeration JavaDoc e = clientResponse.getHeaderFieldNames(); e.hasMoreElements();) {
399             header = (String JavaDoc) e.nextElement();
400             if (log.isDebugEnabled()) {
401                 log.debug("Received header " + header);
402             }
403             String JavaDoc[] val = clientResponse.getHeaderFields(header);
404             if(val == null) {
405                 log.debug("No value???");
406             }
407
408             if (ignoredHeaders.contains(header.toUpperCase())) {
409                 if (log.isDebugEnabled())
410                     log.debug("Ignoring header " + header);
411                 continue;
412             }
413
414             for (int i = 0; i < val.length; i++) {
415                 if (log.isDebugEnabled()) {
416                     log.debug("Adding value " + val[i] + " for " + header);
417                 }
418                 if (i == 0)
419                     response.setField(header, val[i]);
420                 else
421                     response.addField(header, val[i]);
422             }
423         }
424     }
425
426     void processRedirects(HttpResponse clientResponse, RequestHandlerRequest request, RequestHandlerResponse response) {
427
428         /**
429          * Process redirect Location headers, the location may be a HTTP
430          * resource which will require changing to HTTPS
431          */

432         if (clientResponse.getStatus() >= 300 && clientResponse.getStatus() < 400) {
433             switch (clientResponse.getStatus()) {
434                 case 300: // Multiple choices
435
case 301: // Moved permanentley
436
case 302: // Found
437
case 303: // See other
438
case 307: // Temporarily redirect
439
String JavaDoc[] locations = clientResponse.getHeaderFields(HttpConstants.HDR_LOCATION);
440                     response.removeField(HttpConstants.HDR_LOCATION);
441                     for (int i = 0; i < locations.length; i++) {
442                         String JavaDoc originatingHost = clientResponse.getConnection().getHost();
443                         String JavaDoc location = rebuildLocation(Util.urlDecode(locations[i]), request.getHost(), originatingHost);
444                         response.addField("Location", location);
445                         if (log.isDebugEnabled())
446                             log.debug("Location is now '" + location + "'");
447                     }
448                     break;
449                 case 304: // Not Modified
450
// Do nothing return as is
451
break;
452                 case 305: // Use proxy
453
log.warn("Detected HTTP response 305 [Use proxy] this may break reverse proxy!");
454                     break;
455                 default:
456                     log.error("Got unknown 3XX response code from server " + clientResponse.getStatus());
457             }
458         }
459     }
460     
461     static final String JavaDoc rebuildLocation(String JavaDoc location, String JavaDoc host, String JavaDoc originatingHost) {
462         // Check against the requests Host value and change the Location if required
463
if (location.startsWith("http://" + host)) {
464             String JavaDoc protocolStripped = stripProtocol(location);
465             return encodeURL("https://" + protocolStripped);
466         } else if (location.startsWith("http://" + originatingHost) || location.startsWith("https://" + originatingHost)) {
467             String JavaDoc protocolStripped = stripProtocol(location);
468             int indexOf = protocolStripped.indexOf('/');
469             if (indexOf == -1) {
470                 return encodeURL("https://" + host);
471             } else {
472                 String JavaDoc remainingPath = protocolStripped.substring(indexOf);
473                 return encodeURL("https://" + host + remainingPath);
474             }
475         } else {
476             if (log.isDebugEnabled()) {
477                 log.debug("Redirect location may result in reverse proxy error " + location);
478             }
479         }
480         return encodeURL(location);
481     }
482     
483     static final String JavaDoc stripProtocol(String JavaDoc url) {
484         if(url.startsWith("http://")) {
485             return url.substring(7);
486         } else if(url.startsWith("https://")) {
487             return url.substring(8);
488         }
489         return url;
490     }
491     
492     void addCustomHeaders(ReverseProxyWebForward webForward, ProxiedHttpMethod method) {
493
494         /**
495          * Add any custom headers to the request
496          */

497         Map JavaDoc customHeaders = webForward.getCustomHeaders();
498         String JavaDoc header;
499         for (Iterator JavaDoc it = customHeaders.entrySet().iterator(); it.hasNext();) {
500             Map.Entry JavaDoc entry = (Map.Entry JavaDoc) it.next();
501             header = (String JavaDoc) entry.getKey();
502             Vector JavaDoc v = (Vector JavaDoc) entry.getValue();
503             for (Iterator JavaDoc it2 = v.iterator(); it2.hasNext();) {
504                 method.getProxiedRequest().addHeaderField(header, (String JavaDoc) it2.next());
505             }
506         }
507     }
508
509     void checkInsecureIIS(ReverseProxyWebForward webForward, HttpResponse clientResponse) {
510
511         /**
512          * Perform a check to see if we're connected to an IIS server and if the
513          * backend server is insecure. If it is set the customer
514          * Front-End-Https: on header.
515          */

516         String JavaDoc server = clientResponse.getHeaderField("Server");
517
518         if (server != null && server.startsWith("Microsoft-IIS")) {
519             if (!webForward.containsCustomHeader("Front-End-Https"))
520                 webForward.setCustomHeader("Front-End-Https", "on");
521         }
522     }
523
524     void filterUnsupportedAuthMethods(HttpResponse clientResponse) {
525
526         /**
527          * Filter out unsupported authentication methods because they dont work
528          * through the reverse proxy - the best way to enable these will be to
529          * allow credentials to be set on the reverse proxy web forward.
530          */

531         String JavaDoc[] challenges = clientResponse.getHeaderFields("www-authenticate");
532
533         if (challenges != null) {
534             clientResponse.removeFields("www-authenticate");
535
536             for (int i = 0; i < challenges.length; i++) {
537                 if (challenges[i].toLowerCase().startsWith("basic") || challenges[i].toLowerCase().startsWith("digest")
538                     || challenges[i].toLowerCase().startsWith("ntlm")) {
539                     clientResponse.setHeaderField("WWW-Authenticate", challenges[i]);
540                 }
541             }
542         }
543     }
544
545     ProxiedHttpMethod getMethod(HttpClient client, LaunchSession launchSession, RequestHandlerRequest request, URL JavaDoc target) {
546
547         ReverseProxyWebForward webForward = (ReverseProxyWebForward) launchSession.getResource();
548         ProxiedHttpMethod method;
549
550         VariableReplacement v = new VariableReplacement();
551         v.setRequest(request);
552         v.setSession(launchSession.getSession());
553         v.setPolicy(launchSession.getPolicy());
554         
555         /**
556          * POST parameters are now not being
557          */

558
559         if (!webForward.getFormType().equals(WebForwardTypes.FORM_SUBMIT_NONE)
560                 && !webForward.getFormType().equals(WebForwardTypes.FORM_SUBMIT_NONE)
561                 && !webForward.getFormType().equals("")
562                 && !webForward.getFormType().equals(WebForwardTypes.FORM_SUBMIT_JAVASCRIPT)
563                 && !Boolean.TRUE.equals(launchSession.getAttribute(LAUNCH_ATTR_AUTH_POSTED))) {
564
565             /**
566              * This code will automatically submit form parameters. If it is a post,
567              * then we ignore the parameters request and use the webforward target.
568              */

569             method = new ProxiedHttpMethod(webForward.getFormType(),
570                             target.getFile(),
571                             webForward.getFormType().equals(WebForwardTypes.FORM_SUBMIT_POST) ? new MultiMap() : (MultiMap) request.getParameters(),
572                             launchSession.getSession(),
573                             webForward.getFormType().equals(WebForwardTypes.FORM_SUBMIT_POST));
574
575             if (webForward.getCharset() != null
576                     && !webForward.getCharset().equals("")
577                     && !webForward.getCharset().equals(WebForwardTypes.DEFAULT_ENCODING))
578                 method.setCharsetEncoding(webForward.getCharset());
579
580             StringTokenizer JavaDoc tokens = new StringTokenizer JavaDoc(webForward.getFormParameters(), "\n");
581             int idx;
582             String JavaDoc param;
583             
584             while (tokens.hasMoreTokens()) {
585                 param = v.replace(tokens.nextToken().trim());
586                 idx = param.indexOf('=');
587                 if (idx > -1) {
588                     method.addParameter(param.substring(0, idx), param.substring(idx + 1));
589                 } else
590                     method.addParameter(param, "");
591             }
592             
593             launchSession.setAttribute(LAUNCH_ATTR_AUTH_POSTED, Boolean.TRUE);
594             processRequestHeaders(request, method);
595             
596             // Do not send through any cookies on the authentication request
597
method.getProxiedRequest().removeFields(HttpConstants.HDR_COOKIE);
598             client.removeAllCookies();
599
600         } else {
601             method = new ProxiedHttpMethod(request.getMethod(),
602                             request.getURIEncoded(),
603                             (MultiMap) request.getParameters(),
604                             launchSession.getSession(),
605                             request.getContentType() != null && request.getContentType()
606                                             .toLowerCase()
607                                             .startsWith("application/x-www-form-urlencoded"));
608             if (webForward.getCharset() != null
609                     && !webForward.getCharset().equals("")
610                     && !webForward.getCharset().equals(WebForwardTypes.DEFAULT_ENCODING))
611                 method.setCharsetEncoding(webForward.getCharset());
612             processRequestHeaders(request, method);
613         }
614
615         return method;
616     }
617
618     HttpClient getClient(LaunchSession launchSession, URL JavaDoc target) {
619
620         ReverseProxyWebForward webForward = (ReverseProxyWebForward) launchSession.getResource();
621
622         String JavaDoc hostname = target.getHost();
623         boolean isSecure = target.getProtocol().equalsIgnoreCase("https");
624         int connectPort = target.getPort() == -1 ? (isSecure ? 443 : 80) : target.getPort();
625
626         HttpClient client;
627
628         SessionClients clients = null;
629         // CookieMap cookieMap = null;
630
synchronized (launchSession.getSession().getHttpSession()) {
631             clients = (SessionClients) launchSession.getSession().getHttpSession().getAttribute(Constants.HTTP_CLIENTS);
632             if (clients == null) {
633                 clients = new SessionClients();
634                 launchSession.getSession().getHttpSession().setAttribute(Constants.HTTP_CLIENTS, clients);
635             }
636         }
637
638         synchronized (clients) {
639             String JavaDoc key = hostname + ":"
640                 + connectPort
641                 + ":"
642                 + isSecure
643                 + ":"
644                 + webForward.getResourceId()
645                 + ":"
646                 + Thread.currentThread().getName()
647                 + ":"
648                 + launchSession.getSession().getId();
649             client = (HttpClient) clients.get(key);
650
651             if (client == null) {
652                 client = new HttpClient(hostname, connectPort, isSecure);
653                 client.setIncludeCookies(false);
654                 
655                 if (!webForward.getPreferredAuthenticationScheme().equals(HttpAuthenticatorFactory.NONE) && !webForward.getAuthenticationUsername()
656                                 .equals("")
657                     && !webForward.getAuthenticationPassword().equals("")) {
658                     PasswordCredentials pwd = new PasswordCredentials();
659                     pwd.setUsername(SessionInfoReplacer.replace(launchSession.getSession(), webForward.getAuthenticationUsername()));
660                     pwd.setPassword(SessionInfoReplacer.replace(launchSession.getSession(), webForward.getAuthenticationPassword()));
661                     client.setCredentials(pwd);
662                 }
663
664                 // Set the preferred scheme
665
client.setPreferredAuthentication(webForward.getPreferredAuthenticationScheme());
666
667                 // If we're using basic authentication then preempt the 401
668
// response
669
client.setPreemtiveAuthentication(webForward.getPreferredAuthenticationScheme().equalsIgnoreCase("BASIC"));
670
671                 clients.put(key, client);
672             }
673         }
674
675         return client;
676     }
677
678     void setRequestEncoding(LaunchSession launchSession, URL JavaDoc target, RequestHandlerRequest request) {
679
680         ReverseProxyWebForward webForward = (ReverseProxyWebForward) launchSession.getResource();
681
682         /**
683          * This code sets the character encoding of the request. This may be
684          * overridden because some servers assume the character set and there is
685          * no way for us work this.
686          */

687         try {
688             if (webForward.getCharset() != null
689                     && !webForward.getCharset().equals("")
690                     && !webForward.getCharset().equals(WebForwardTypes.DEFAULT_ENCODING))
691                 request.setCharacterEncoding(webForward.getCharset());
692         } catch (UnsupportedEncodingException JavaDoc ex) {
693             log.error("Java runtime does not support encoding", ex);
694         }
695         CoreServlet.getServlet().fireCoreEvent(new ResourceAccessEvent(this,
696                         WebForwardEventConstants.WEB_FORWARD_RESOURCE_LOADED,
697                         webForward,
698                         launchSession.getPolicy(),
699                         launchSession.getSession(),
700                         CoreEvent.STATE_SUCCESSFUL).addAttribute(WebForwardEventConstants.EVENT_ATTR_WEB_FORWARD_URL,
701             target.toExternalForm()));
702     }
703
704     SessionInfo locateSession(String JavaDoc pathInContext, String JavaDoc pathParams, RequestHandlerRequest request,
705                                 RequestHandlerResponse response) {
706         /*
707          * When not authenticated, dont reverse proxy anything. We use the logon
708          * ticket to get the HttpSession in use
709          */

710         SessionInfo session = null;
711
712         /**
713          * The launching of a reverse proxy will always be a GET. This change
714          * will allow us to set the character encoding of the request later so
715          * that POST parameters are not incorrectly encoded.
716          */

717         if (request.getMethod().equals("GET") && request.getParameters().containsKey(LaunchSession.LONG_LAUNCH_ID)) {
718             String JavaDoc launchId = (String JavaDoc) request.getParameters().get(LaunchSession.LONG_LAUNCH_ID);
719
720             // Get the actual session for the reverse proxy
721
LaunchSession launchSession = LaunchSessionFactory.getInstance().getLaunchSession(launchId);
722             if (launchSession != null) {
723
724                 // If the launch session is not for a reverse proxy web forward
725
// then ignore
726
if (launchSession.isTracked() && launchSession.getResource() instanceof ReverseProxyWebForward) {
727                     session = launchSession.getSession();
728
729                     Cookie JavaDoc[] cookies = request.getCookies();
730                     if (cookies != null) {
731                         for (int i = 0; i < cookies.length; i++) {
732                             if (cookies[i].getName().equalsIgnoreCase(sessionCookie)) {
733                                 LogonControllerFactory.getInstance().attachSession(cookies[i].getValue(), session);
734                                 break;
735                             }
736                         }
737                     }
738
739                     LogonControllerFactory.getInstance().addCookies(request, response, session.getLogonTicket(), session);
740                 }
741             }
742
743         } else {
744             Cookie JavaDoc[] cookies = request.getCookies();
745
746             if (cookies != null) {
747                 for (int i = 0; i < cookies.length; i++) {
748                     if (cookies[i].getName().equalsIgnoreCase(sessionCookie)) {
749                         session = LogonControllerFactory.getInstance().getSessionInfoBySessionId(cookies[i].getValue());
750                         if (session != null) {
751                             LogonControllerFactory.getInstance().addCookies(request, response, session.getLogonTicket(), session);
752                             session.access();
753                             break;
754                         }
755                     }
756                     if (cookies[i].getName().equalsIgnoreCase(Constants.DOMAIN_LOGON_TICKET) || cookies[i].getName()
757                                     .equalsIgnoreCase(Constants.LOGON_TICKET)) {
758                         session = LogonControllerFactory.getInstance().getSessionInfo(cookies[i].getValue());
759                         if (session != null) {
760                             LogonControllerFactory.getInstance().addCookies(request, response, session.getLogonTicket(), session);
761                             session.access();
762                             break;
763                         }
764                     }
765
766                 }
767             }
768         }
769
770         if (session != null) {
771             session.access();
772         }
773
774         return session;
775     }
776     
777     /**
778      * Takes an unencoded URL query string, and encodes it.
779      * @param query
780      * @return
781      */

782     public static final String JavaDoc encodeQuery(String JavaDoc query) {
783         String JavaDoc encoded = "";
784         StringTokenizer JavaDoc pairs = new StringTokenizer JavaDoc(query, "&");
785         while(pairs.hasMoreTokens()) {
786             StringTokenizer JavaDoc pair = new StringTokenizer JavaDoc(pairs.nextToken(), "=");
787             if(pair.hasMoreTokens()) {
788                 encoded += (encoded.length()==0 ? "" : "&") + URLUTF8Encoder.encode(pair.nextToken(), true);
789                 if(pair.hasMoreTokens()) {
790                     encoded += "=" + URLUTF8Encoder.encode(pair.nextToken(), true);
791                 }
792                 
793             }
794         }
795         return encoded;
796     }
797
798     /**
799      * Encodes a URL
800      * @param location
801      * @return
802      */

803     public static final String JavaDoc encodeURL(String JavaDoc location) {
804         
805         try {
806             URL JavaDoc url = new URL JavaDoc(location);
807             return url.getProtocol() + "://" + (url.getUserInfo()==null ? "" : DAVUtilities.encodeURIUserInfo(url.getUserInfo()) + "@")
808                 + url.getHost() + (url.getPath()==null ? "" : URLUTF8Encoder.encode(url.getPath(), false)) + (url.getQuery()==null ? "" : "?" + encodeQuery(url.getQuery()));
809         } catch (MalformedURLException JavaDoc e) {
810             
811             int idx = location.indexOf('?');
812             if(idx > -1 && idx < location.length()-1) {
813                 return URLUTF8Encoder.encode(location.substring(0, idx), false) + "?" + encodeQuery(location.substring(idx+1));
814             } else
815                 return URLUTF8Encoder.encode(location, false);
816         }
817     }
818
819 }
820
Popular Tags