001: /*
002: * $Id: CookieParser.java,v 1.10 2006/02/28 00:21:43 js10465 Exp $
003: * $Source: /m/portal/ps/srap/src/com/sun/portal/rproxy/connectionhandler/CookieParser.java,v $
004: * $Log: CookieParser.java,v $
005: * Revision 1.10 2006/02/28 00:21:43 js10465
006: * cr6356345: crt333: final part of fix for london biz school escalation
007: * against 6.3.1. Sync to trunk.
008: *
009: * Revision 1.9 2006/01/27 23:21:32 js10465
010: * Forward-port fix for 6.3.1 escalation. CRT333/334, CR 6356345 6365332
011: *
012: * Revision 1.8 2005/11/30 11:27:21 ss150821
013: * 6356996 - Srap Code base needs to save files in the unix file format and not windows
014: *
015: * Revision 1.7 2005/02/24 07:36:44 ss150821
016: * RFE 6223490 - SRA Should use JDK based logging
017: *
018: * Revision 1.6 2005/02/23 09:15:04 ss150821
019: * RFE 6223490 - SRA Should use JDK based logging
020: *
021: * Revision 1.5 2003/08/13 15:16:58 mm132998
022: * Bug 4849956
023: *
024: * Revision 1.4 2003/08/13 14:48:38 mm132998
025: * Bug 4793026 , Handle for Session cookie also
026: *
027: * Revision 1.3 2003/07/15 13:04:40 mm132998
028: * Beta showstopper - unresolved issues
029: *
030: * Revision 1.2 2003/07/10 16:51:32 mm132998
031: * Multiple cookies have to be ordered and sent, not replaced
032: *
033: * Revision 1.1 2003/07/10 14:15:00 mm132998
034: * Cookie Parser
035: *
036: *
037: */
038: /*
039: * CookieParser.java
040: *
041: * Created on July 1, 2003, 10:46 AM
042: */
043:
044: package com.sun.portal.rproxy.connectionhandler;
045:
046: import java.net.MalformedURLException;
047: import java.net.URL;
048: import java.net.URLDecoder;
049: import java.net.URLEncoder;
050: import java.util.Collections;
051: import java.util.Hashtable;
052: import java.util.Iterator;
053: import java.util.LinkedList;
054: import java.util.List;
055: import java.util.Set;
056: import java.util.StringTokenizer;
057:
058: import com.sun.portal.rproxy.configservlet.client.GatewayProfile;
059: import com.sun.portal.util.SystemProperties;
060:
061: /*
062: * Handles all the cookie modification and restoration when cookie handling is
063: * enabled at gateway.
064: *
065: * @author Mridul Muralidharan
066: */
067: public class CookieParser {
068:
069: private static final byte crlf[] = { 13, 10 };
070:
071: private static final String scrlf = new String(crlf);
072:
073: private static final String SET_COOKIE = "Set-Cookie";
074:
075: private static String sessionCookieName;
076:
077: private static String gatewaySetCookieDomain = null;
078: static {
079: sessionCookieName = com.iplanet.am.util.SystemProperties.get(
080: "com.iplanet.am.cookie.name", "iPlanetDirectoryPro");
081: gatewaySetCookieDomain = SystemProperties.get(
082: "gateway.setcookie.domain", null);
083: }
084:
085: private static final boolean _useHTTPProxy = GatewayProfile
086: .getBoolean("UseHTTPProxy", false);
087:
088: private static boolean setCookiesAsSecure = GatewayProfile
089: .getBoolean("MarkCookiesSecure", false);
090:
091: public static String modifyCookieHeader(HTTPResponse resp,
092: Request req, String cookie_header) {
093:
094: if (cookie_header == null) {
095: return null;
096: }
097:
098: int index;
099:
100: index = cookie_header.indexOf(':');
101: if (index == -1 || index + 1 == cookie_header.length()) {
102: return (cookie_header);
103: }
104:
105: String cookie = cookie_header.substring(index + 1).trim();
106:
107: StringTokenizer tokens = new StringTokenizer(cookie, ";");
108:
109: if (!tokens.hasMoreTokens()) {
110: return cookie_header;
111: }
112:
113: String nameAndValue = tokens.nextToken().trim();
114:
115: if (nameAndValue.startsWith(sessionCookieName + "=")) {
116: // System.out.println("setCookiesAsSecure : " + setCookiesAsSecure);
117: // System.out.println("req.getGatewayURL() : " +
118: // req.getGatewayURL());
119: if (setCookiesAsSecure
120: && req.getGatewayURL().regionMatches(true, 0,
121: "https", 0, 5)) {
122: cookie_header = cookie_header.trim();
123: while (cookie_header.endsWith("\r")
124: || cookie_header.endsWith("\n")) {
125: cookie_header = cookie_header.substring(0,
126: cookie_header.length() - 1);
127: }
128: if (cookie_header.endsWith(";")) {
129: cookie_header = cookie_header + "; secure" + scrlf;
130: } else {
131: cookie_header = cookie_header + "; secure" + scrlf;
132: }
133: }
134: // System.out.println("cookie_header : " + cookie_header);
135: return cookie_header;
136: }
137:
138: int equIndex;
139: // Bug ID - # 4664279
140: equIndex = nameAndValue.indexOf('=');
141: if (equIndex != -1) {
142: // URLEncode the cookie value so that any '|' in the value gets
143: // encoded
144: // and doesn't interfere with our cookie rewriting.
145: String tmpValue = nameAndValue.substring(equIndex + 1);
146: try {
147: tmpValue = URLEncoder.encode(tmpValue);
148: nameAndValue = nameAndValue.substring(0, equIndex + 1)
149: + tmpValue;
150: } catch (Exception ex) {
151: }
152: }
153: // EOC : Bug ID - # 4664279
154:
155: StringBuffer sb = new StringBuffer();
156: String token, attr, val;
157: String path = null;
158: String domain = null;
159: boolean domainAppended = false;
160: boolean pathAppended = false;
161:
162: String reqHost = req.getHost();
163: String reqPath = req.getObject();
164:
165: //BEGIN CR6356345
166: int lastSlashIndex = reqPath.lastIndexOf('/');
167: if (lastSlashIndex == -1) {
168: reqPath = "/";
169: } else if (reqPath.length() > 1) {
170: reqPath = reqPath.substring(0, lastSlashIndex + 1);
171: }
172: //END CR6356345
173:
174: if (_useHTTPProxy) {
175: reqHost = req.getURL();
176: // URL is expected to be of form /http://host:port/path
177: // The port may or maynot exist.
178: int tmpIndx = reqHost.indexOf(':') + 3;
179: int tmpIndx1 = reqHost.indexOf(':', tmpIndx);
180: int indxSlash = reqHost.indexOf('/', tmpIndx);
181:
182: if (indxSlash == -1) {
183: // Dont think this can happen.
184: indxSlash = reqHost.length();
185: reqPath = "/";
186: } else {
187: reqPath = reqHost.substring(indxSlash);
188: }
189: if (tmpIndx1 == -1) {
190: // URL's of form /proto://host/path
191: reqHost = reqHost.substring(tmpIndx, indxSlash);
192: } else {
193: if (indxSlash < tmpIndx1) {
194: // URL's of form : /proto://host/path:path_cont
195: reqHost = reqHost.substring(tmpIndx, indxSlash);
196: } else {
197: // URL's of form : /proto://host:port/path:path_cont
198: reqHost = reqHost.substring(tmpIndx, tmpIndx1);
199: }
200: }
201: }
202:
203: while (tokens.hasMoreTokens()) {
204: token = tokens.nextToken().trim();
205: if (token.length() == 0) {
206: continue;
207: }
208:
209: equIndex = token.indexOf('=');
210:
211: if (equIndex < 0) {
212: attr = token;
213: val = null;
214: } else {
215: attr = token.substring(0, equIndex).trim();
216: if (equIndex + 1 == token.length()) {
217: val = null;
218: } else {
219: val = token.substring(equIndex + 1).trim();
220: }
221: }
222:
223: if (attr.equalsIgnoreCase("path")) {
224: path = val;
225: if (path != null) {
226: if (!reqPath.startsWith(path)) {
227: return null;
228: }
229: }
230: } else if (attr.equalsIgnoreCase("domain")) {
231: domain = val;
232: if (domain != null) {
233: // must start with '.' and at least .a.b
234: /*
235: * if (domain.charAt(0) != '.' || domain.length() < 4) {
236: * return null; }
237: */
238: if (domain.length() < 3) {
239: return null;
240: }
241: if (domain.charAt(domain.length() - 1) == '.') {
242: return null;
243: }
244:
245: // BUG ID : 4705991
246: if (!reqHost.toLowerCase().endsWith(
247: domain.toLowerCase())) {
248: return null;
249: }
250: }
251:
252: } else {
253: sb.append("; " + token);
254: }
255: }
256:
257: StringBuffer sbnv = new StringBuffer(2 * nameAndValue.length());
258: sbnv.append(SET_COOKIE).append(": ");
259: // Bug 4821960
260: // We use '_' as our delimiter , so we have to replace it with something
261: // else.
262: if (path != null)
263: sbnv.append(URLEncoder.encode(path.replace('_', ';')));
264: // Bug ID : 4705244
265: if (domain != null)
266: sbnv.append(URLEncoder.encode(domain.replace('_', ';')));
267:
268: // Encode reqHost so that we elimiate all ';' characters - then replace
269: // all _ with ;
270: // and then encode again. Hence our delimiter is not hit at all !
271: else
272: sbnv.append(URLEncoder.encode(URLEncoder.encode(reqHost)
273: .replace('_', ';')));
274: sbnv.append("_");
275:
276: sbnv.append(nameAndValue);
277:
278: sbnv.append("|");
279:
280: // fix for BUG# 4468740
281:
282: String gwHost = SystemProperties.get("gateway.host", null);
283: String reqGWHost = req.getGatewayHost();
284:
285: // Bug ID : 4783937
286: if (gwHost != null) {
287: if (reqGWHost != null) {
288: if (!reqGWHost.equalsIgnoreCase(gwHost)) {
289: // Virtual host being used - so modify gwHost accordingly.
290: try {
291: URL tmpUrl = new URL(req.getGatewayURL());
292: gwHost = tmpUrl.getHost();
293: } catch (MalformedURLException ex) {
294: }
295: }
296: }
297: } else {
298: gwHost = reqGWHost;
299: }
300: // If gateway is top level domain - then dont set the gateway domain.
301: if (gwHost != null
302: && gwHost.indexOf('.') == gwHost.lastIndexOf('.')) {
303: // Single or no dots !!!
304: gwHost = null;
305: }
306:
307: String gwDomain = null;
308: if (gatewaySetCookieDomain != null) {
309: gwDomain = gatewaySetCookieDomain;
310: if (gwDomain.trim().length() == 0) {
311: gwDomain = null;
312: }
313: } else {
314: if (gwHost != null && gwHost.indexOf('.') != -1) {
315: gwDomain = gwHost.substring(gwHost.indexOf('.'))
316: .toLowerCase();
317: }
318: }
319: if (gwDomain != null) {
320: sb.append("; domain=");
321: // Bug id # 4652682
322: // String gwdomain = gwHost.substring(gwHost.indexOf('.'));
323: // EOC : Bug id # 4652682
324: sb.append(gwDomain);
325: }
326:
327: if (domain != null) {
328: sbnv.append(domain);
329: } else {
330: // Bug id # 4652682
331: sbnv.append(reqHost.toLowerCase());
332: // EOC : Bug id # 4652682
333: }
334:
335: sbnv.append("|");
336: sb.append("; path=/");
337: if (path != null) {
338: sbnv.append(path);
339: } else {
340: // String s = req.getObject();
341: String s = reqPath;
342: if (s == null) {
343: sbnv.append("/");
344: } else {
345: int i = s.lastIndexOf('/');
346: if (i < 1) {
347: sbnv.append("/");
348: } else {
349: sbnv.append(s.substring(0, i));
350: }
351: }
352: }
353:
354: if (setCookiesAsSecure
355: && req.getGatewayURL().regionMatches(true, 0, "https",
356: 0, 5)) {
357: sb.append("; secure");
358: }
359: sbnv.append("|iplanet");
360: sbnv.append(sb).append(scrlf);
361:
362: return sbnv.toString();
363: }
364:
365: public static void restoreCookieHeader(Request req) {
366: String cookie_header = req.getRequestHeader("Cookie");
367:
368: if (cookie_header == null) {
369: return;
370: }
371:
372: int index;
373:
374: index = cookie_header.indexOf(':');
375:
376: if (index == -1 || index + 1 == cookie_header.length()) {
377: return;
378: }
379:
380: String cookies = cookie_header.substring(index + 1).trim();
381:
382: StringTokenizer tokens = new StringTokenizer(cookies, ";");
383:
384: String token, st;
385:
386: String reqHost = req.getHost();
387: String reqPath = req.getObject();
388:
389: //BEGIN CR6356345
390: int lastSlashIndex = reqPath.lastIndexOf('/');
391: if (lastSlashIndex == -1) {
392: reqPath = "/";
393: } else if (reqPath.length() > 1) {
394: reqPath = reqPath.substring(0, lastSlashIndex + 1);
395: }
396: //END CR6356345
397:
398: if (_useHTTPProxy) {
399: reqHost = req.getURL();
400: // URL is expected to be of form /http://host:port/path
401: // The port may or maynot exist.
402: int tmpIndx = reqHost.indexOf(':') + 3;
403: int tmpIndx1 = reqHost.indexOf(':', tmpIndx);
404: int indxSlash = reqHost.indexOf('/', tmpIndx);
405:
406: if (indxSlash == -1) {
407: // Dont think this can happen.
408: indxSlash = reqHost.length();
409: reqPath = "/";
410: } else {
411: reqPath = reqHost.substring(indxSlash);
412: }
413: if (tmpIndx1 == -1) {
414: // URL's of form /proto://host/path
415: reqHost = reqHost.substring(tmpIndx, indxSlash);
416: } else {
417: if (indxSlash < tmpIndx1) {
418: // URL's of form : /proto://host/path:path_cont
419: reqHost = reqHost.substring(tmpIndx, indxSlash);
420: } else {
421: // URL's of form : /proto://host:port/path:path_cont
422: reqHost = reqHost.substring(tmpIndx, tmpIndx1);
423: }
424: }
425: }
426:
427: StringBuffer sb = new StringBuffer("Cookie:");
428: int index1, index2, index3;
429: String domain, path, orig_cookie;
430: Hashtable cookieTable = new Hashtable();
431:
432: while (tokens.hasMoreTokens()) {
433: token = tokens.nextToken().trim();
434: if (!token.endsWith("|iplanet")) {
435: sb.append(" " + token + ";");
436: continue;
437: }
438: index1 = token.indexOf("_");
439: st = token.substring(index1 + 1);
440: token = st;
441: index1 = token.lastIndexOf('|');
442: if (index1 < 2) {
443: sb.append(" ").append(token).append(";");
444: continue;
445: }
446: index2 = token.lastIndexOf('|', index1 - 1);
447: if (index2 < 1) {
448: sb.append(" ").append(token).append(";");
449: continue;
450: }
451: index3 = token.lastIndexOf('|', index2 - 1);
452: if (index3 < 0) {
453: sb.append(" ").append(token).append(";");
454: continue;
455: }
456: if ((index3 + 1 == index2) || (index2 + 1 == index1)) {
457: sb.append(" ").append(token).append(";");
458: continue;
459: }
460: domain = token.substring(index3 + 1, index2).trim();
461: path = token.substring(index2 + 1, index1).trim();
462:
463: boolean domainCheck = false;
464: domainCheck = reqHost.toLowerCase().endsWith(
465: domain.toLowerCase());
466:
467: if (domainCheck && reqPath.startsWith(path)) {
468:
469: orig_cookie = token.substring(0, index3).trim();
470: // Bug ID - # 4664279
471: index1 = orig_cookie.indexOf('=') + 1;
472: if (orig_cookie.indexOf('%', index1) != -1) {
473: // We may have done a sucessful encode
474: try {
475: String newValue = URLDecoder.decode(orig_cookie
476: .substring(index1));
477: orig_cookie = orig_cookie.substring(0, index1)
478: + newValue;
479: } catch (Exception ex) {
480: }
481: }
482: // EOC : Bug ID - # 4664279
483: // Add to our hashtable ...
484: int valIndex = orig_cookie.indexOf('=');
485: if (valIndex != -1) {
486: String name = orig_cookie.substring(0, valIndex);
487: List list = (List) cookieTable.get(name);
488: if (list == null) {
489: list = new LinkedList();
490: list.add(new CookieInfoContainer(orig_cookie,
491: domain, path));
492: cookieTable.put(name, list);
493: } else {
494: list.add(new CookieInfoContainer(orig_cookie,
495: domain, path));
496: }
497: } else {
498: sb.append(" ").append(orig_cookie).append(";");
499: }
500: }
501: }
502:
503: // Go through the cookieTable and send cookie matching most appropriate
504: // path and domain.
505: // First priority - path , then most suitably matching domain.
506: Set cookieSet = cookieTable.keySet();
507: Iterator iter = cookieSet.iterator();
508:
509: while (iter.hasNext()) {
510: String name = (String) iter.next();
511: List list = (List) cookieTable.get(name);
512: sb.append(" ").append(findBestCookieMatch(list))
513: .append(";");
514: }
515:
516: int len = sb.length();
517: if (sb.charAt(len - 1) == ';') {
518: sb.setLength(len - 1);
519: }
520:
521: req.setRequestHeader("Cookie", sb.toString() + scrlf);
522: }
523:
524: private static String findBestCookieMatch(List cookieList) {
525: // Ok easy parsing , get cookie with longest path.
526: // If multiple matches , then get cookie with longest domain value :)
527: // Since this cookie is a valid cookie - that is domain and path match ,
528: // this will
529: // ensure correct parsing.
530: Collections.sort(cookieList);
531: StringBuffer sb = new StringBuffer();
532: Iterator iter = cookieList.iterator();
533: while (iter.hasNext()) {
534: sb.append(((CookieInfoContainer) iter.next()).getCookie());
535: if (iter.hasNext()) {
536: //sb.append(" ; ");
537: sb.append("; ");
538: }
539: }
540: return sb.toString();
541: }
542: }
543:
544: class CookieInfoContainer implements Comparable {
545:
546: private String cookie = null;
547:
548: private String domain = null;
549:
550: private String path = null;
551:
552: CookieInfoContainer(String cookie, String domain, String path) {
553: this .cookie = cookie.trim();
554: this .domain = domain.trim();
555: this .path = path.trim();
556: }
557:
558: public String getCookie() {
559: return cookie;
560: }
561:
562: public String getDomain() {
563: return domain;
564: }
565:
566: public String getPath() {
567: return path;
568: }
569:
570: public int compareTo(java.lang.Object obj) {
571: if (obj == null) {
572: throw new NullPointerException("Null object !");
573: }
574: CookieInfoContainer other = (CookieInfoContainer) obj;
575:
576: return -(getPath().length() - other.getPath().length());
577: }
578: }
|