001: /*
002: * HTTPSRetriever.java
003: *
004: * $Author: np145014 $
005: *
006: * $Date: 2005/03/01 10:29:51 $ $Revision: 1.12 $
007: *
008: * Copyright (c) 1996 Sun Microsystems, Inc. All Rights Reserved.
009: *
010: * Developed by SunPS and SunIR
011: */
012:
013: package com.sun.portal.rproxy.connectionhandler;
014:
015: import java.io.IOException;
016: import java.io.InputStream;
017: import java.io.OutputStream;
018: import java.io.UnsupportedEncodingException;
019: import java.net.Socket;
020: import java.util.StringTokenizer;
021: import java.util.logging.Level;
022: import java.util.logging.Logger;
023:
024: import javax.net.ssl.SSLSession;
025:
026: import sun.security.AuthContext;
027: import sun.security.ssl.SSLSocketImpl;
028:
029: import com.sun.portal.log.common.PortalLogger;
030: import com.sun.portal.rproxy.configservlet.client.GatewayProfile;
031: import com.sun.portal.rproxy.monitoring.MonitoringSubsystem;
032: import com.sun.portal.util.DomainWebProxyConfig;
033: import com.sun.portal.util.ServiceIdentifier;
034: import com.sun.portal.util.SystemProperties;
035: import com.sun.portal.util.SRAEvent;
036:
037: /**
038: * This class retrieves objects using the HTTPS protocol.
039: *
040: * @author Gabriel Lawrence
041: */
042: // JP_Declaration SSLHTTPSRetriever 193
043: public class SSLHTTPSRetriever extends HTTPRetriever {
044:
045: private static final String DEFAULT_SSL_PORT = "443";
046:
047: // private static String sslPort;
048: private SSLSession session;
049:
050: public static String currentReqHost;
051:
052: private static String rpSubdomain;
053:
054: private static String rpDomain;
055:
056: // private static Logger logger =
057: // Logger.getLogger("com.sun.portal.sra.rproxy");
058: private static Logger logger = PortalLogger
059: .getLogger(SSLHTTPSRetriever.class);
060:
061: static {
062: String _host = SystemProperties.get("gateway.host", null);
063:
064: String rphost = "https://" + _host + "/";
065: // sslPort = PlatformProfile.getString("serverPort", DEFAULT_SSL_PORT);
066:
067: if (rphost != null) {
068: int len = rphost.length();
069: int index1 = rphost.indexOf('.');
070: if (index1 != -1 && index1 + 1 < len) {
071: int index2 = rphost.indexOf('.', index1 + 1);
072: if (index2 == -1) {
073: rpSubdomain = rphost.substring(index1 + 1);
074: } else {
075: rpSubdomain = rphost.substring(index1 + 1, index2);
076: rpDomain = rphost.substring(index2);
077: }
078: }
079: }
080: }
081:
082: // JP_Operation getServerCertificate() 127
083: public byte[] getServerCertificate() {
084: return null;
085: }
086:
087: private static boolean doBasicAuthentication = false;
088: static {
089: doBasicAuthentication = GatewayProfile.getBoolean(
090: "DoBasicAuthentication", false)
091: && ServiceIdentifier.isGateway();
092: }
093:
094: /**
095: * Get a response for a specific Request
096: */
097: public Response getResponse(Request req, String destinationHost,
098: Integer logId) {
099: CachedSocket s = null;
100:
101: String password = null;
102: boolean found_pw = false;
103:
104: if (doBasicAuthentication) {
105: password = req.getRequestHeader("Authorization");
106:
107: if (password == null) {
108: found_pw = BasicAuthentication.getPassword(req,
109: destinationHost);
110: }
111: // Lihue Bug ID - 4618949
112: else {
113: String basic = password.substring(
114: password.indexOf(':') + 1).trim();
115: if (!basic.regionMatches(true, 0, "basic ", 0, 5)) {
116: password = null;
117: }
118: }
119: // EOC : Lihue Bug ID - 4618949
120: }
121: // Lihue PRD : 7.4.3.2
122:
123: Response result = new HTTPResponse();
124: try {
125: // logger.info("SSLHTTPSRetriever: AttemptRetrieve " + req);
126: Object[] params0 = { req };
127: logger.log(Level.INFO, "PSSRRPROXY_CSPRCONHNDLR118",
128: params0);
129:
130: if (req.getUseProxy()) {
131: String prxyhost = req.getProxyHost();
132: String headerProxyAuth = req
133: .getRequestHeader("Proxy-Authorization");
134: if (headerProxyAuth == null) {
135: String proxy_passwd = DomainWebProxyConfig
136: .getProxyPassword(prxyhost);
137: if (proxy_passwd != null) {
138: req.setRequestHeader("Proxy-Authorization",
139: "Proxy-Authorization: Basic "
140: + proxy_passwd);
141: }
142: }
143: s = createTunnelSocket(req);
144:
145: // logger.info("SSLHTTPSRetriever: Connecting to " +
146: // req.getProxyHost());
147: Object[] params1 = { req.getProxyHost() };
148: logger.log(Level.INFO, "PSSRRPROXY_CSPRCONHNDLR119",
149: params1);
150:
151: } else {
152: s = SSLCachedSSLSocketFactory.getCachedSocket(req
153: .getHost(), Integer.parseInt(req.getPort()),
154: "ssl", logId);
155: // logger.info("SSLHTTPSRetriever: Connecting to: " +
156: // req.getHost());
157: Object[] params2 = { req.getHost() };
158: logger.log(Level.INFO, "PSSRRPROXY_CSPRCONHNDLR120",
159: params2);
160: }
161:
162: // logger.info("SSLHTTPSRetriever: Connecting to: " +
163: // req.getHost());
164: Object[] params3 = { req.getHost() };
165: logger.log(Level.INFO, "PSSRRPROXY_CSPRCONHNDLR121",
166: params3);
167:
168: if (s == null) {
169: logger
170: .warning("SSLHTTPSRetriever: Null socket returned. Probably couldn't resolve host.");
171: return null;
172: }
173:
174: ForceSSLHandshake(req, s);
175:
176: CSBufferedInputStream in;
177: try {
178: sendRequest(req, s);
179: in = s.getInputStream();
180: getResponseHeader((HTTPResponse) result, in, req);
181: } catch (Exception e) {
182: // logger.log(Level.SEVERE, "Exception while sending
183: // request/recieving response", e);
184: logger.log(Level.SEVERE, "PSSRRPROXY_CSPRCONHNDLR122",
185: e);
186: // e.printStackTrace();
187: return null;
188:
189: }
190: if (doBasicAuthentication) {
191: if (result.getStatusCode().compareTo("401") != 0
192: && result.getStatusCode().compareTo("403") != 0) {
193:
194: if (password != null) {
195: BasicAuthentication.storePassword(req,
196: destinationHost);
197: }
198: }
199: }
200: // Get content length from response header. If not known then set it
201:
202: // to the number of available bytes in the stream.
203: String cl = result.getResponseHeader("content-length");
204: int length = 0;
205: if (cl != null) {
206: length = Integer.parseInt(cl.substring(
207: cl.indexOf(':') + 1).trim());
208: } else {
209: length = -1; // indicates length is unknown
210: }
211:
212: /*
213: * //Look for a keep-alive timeout value to use for socket timeout
214: * value String ka = result.getResponseHeader("keep-alive"); if (ka !=
215: * null) { int to =
216: * Integer.parseInt(ka.substring(ka.indexOf("timeout=")+8,
217: * ka.indexOf(','))); if (to > 0) s.setTimeout(to); } // Check if
218: * socket is to be closed after buffer has been read. if
219: * (result.getResponseHeader("Connection: close") != null)
220: * in.setClosed(); else in.setKeepAlive();
221: */
222: in.setClosed();
223:
224: // Set the content stream with the CachedSocket and set buffer
225: // length.
226: // Length is number of bytes or -1 if unknown
227: ((CSBufferedInputStream) in).setLength(length);
228: ((HTTPResponse) result).setContentStream(in);
229: result.setSocket(s);
230: } catch (Exception ex) {
231: // logger.log(Level.SEVERE, "SSLHTTPSRetriever: ErrorRetrieve " +
232: // req, ex);
233: Object[] params5 = { req, ex };
234: logger.log(Level.SEVERE, "PSSRRPROXY_CSPRCONHNDLR123",
235: params5);
236: // ex.printStackTrace();
237:
238: result = null;
239: /**
240: * Bug 4710658
241: */
242: if (s != null) {
243: try {
244: s.close();
245: MonitoringSubsystem
246: .handleEvent(SRAEvent.SSL_SOCKET_DESTROYED);
247: } catch (IOException e) {
248: }
249: }
250: // End of code change for Bug 4710658
251:
252: }
253: return result;
254: }
255:
256: //
257: // Tell our tunnel where we want to CONNECT, and look for the
258: // right reply. Throw IOException if anything goes wrong.
259: //
260: private CachedSocket createTunnelSocket(Request req)
261: throws IOException {
262: Socket tunnel = new Socket(req.getProxyHost(), req
263: .getProxyPort());
264: MonitoringSubsystem.handleEvent(SRAEvent.PLAIN_SOCKET_CREATED);
265: String prxyhost = req.getProxyHost();
266: String headerProxyAuth = req
267: .getRequestHeader("Proxy-Authorization");
268: String proxy_passwd = null;
269: if (headerProxyAuth == null) {
270: proxy_passwd = DomainWebProxyConfig
271: .getProxyPassword(prxyhost);
272: if (proxy_passwd != null) {
273: req.setRequestHeader("Proxy-Authorization",
274: "Proxy-Authorization: Basic " + proxy_passwd);
275: }
276: }
277:
278: OutputStream out = tunnel.getOutputStream();
279: String msg = null;
280: if (proxy_passwd == null) {
281: msg = "CONNECT "
282: + req.getHost()
283: + ":"
284: + Integer.parseInt(req.getPort())
285: + " HTTP/1.0\n"
286: + "User-Agent: "
287: + sun.net.www.protocol.http.HttpURLConnection.userAgent
288: + "\r\n\r\n";
289: } else {
290: msg = "CONNECT "
291: + req.getHost()
292: + ":"
293: + Integer.parseInt(req.getPort())
294: + " HTTP/1.0\n"
295: + "Proxy-Authorization: Basic "
296: + proxy_passwd
297: + "User-Agent: "
298: + sun.net.www.protocol.http.HttpURLConnection.userAgent
299: + "\r\n\r\n";
300: }
301: byte b[];
302: try {
303: // We really do want ASCII7 -- the http protocol doesn't change
304: // with locale.
305: b = msg.getBytes("ASCII7");
306: } catch (UnsupportedEncodingException ignored) {
307: // If ASCII7 isn't there, something serious is wrong, but
308: // Paranoia Is Good (tm)
309: b = msg.getBytes();
310: }
311: out.write(b);
312: out.flush();
313:
314: // We need to store the reply so we can create a detailed
315: // error message to the user.
316: byte reply[] = new byte[200];
317: int replyLen = 0;
318: int newlinesSeen = 0;
319: boolean headerDone = false; // Done on first newline
320: InputStream in = tunnel.getInputStream();
321: boolean error = false;
322:
323: while (newlinesSeen < 2) {
324: int i = in.read();
325: if (i < 0) {
326: throw new IOException("Unexpected EOF from proxy");
327: }
328: if (i == '\n') {
329: headerDone = true;
330: ++newlinesSeen;
331: } else if (i != '\r') {
332: newlinesSeen = 0;
333: if (!headerDone && replyLen < reply.length) {
334: reply[replyLen++] = (byte) i;
335: }
336: }
337: }
338:
339: // Converting the byte array to a string is slightly wasteful
340: // in the case where the connection was successful, but it's
341: // insignificant compared to the network overhead.
342: String replyStr;
343: try {
344: replyStr = new String(reply, 0, replyLen, "ASCII7");
345: } catch (UnsupportedEncodingException ignored) {
346: replyStr = new String(reply, 0, replyLen);
347: }
348:
349: // We asked for HTTP/1.0, so we should get that back
350: if (!replyStr.startsWith("HTTP/1.0 200")) {
351: throw new IOException("Unable to tunnel through "
352: + req.getProxyHost() + ":" + req.getProxyPort()
353: + ". Proxy returns \"" + replyStr + "\"");
354: }
355:
356: // tunneling Handshake was successful!
357:
358: SSLSocketImpl s = new SSLSocketImpl(tunnel, AuthContext
359: .getDefault(), req.getHost(), Integer.parseInt(req
360: .getPort()));
361: return (SSLCachedSSLSocketFactory.createSocket(s));
362:
363: }
364:
365: public void ForceSSLHandshake(Request req, CachedSocket s)
366: throws IOException {
367: // this function will set currentReqHost. ReverseProxyTrustDecider.rptd
368: // isTrustedFor() will read it and determine if we are going to trust
369: // certificate signed by unknown CA
370: // currentReqHost will be either fully qualified host name or ip
371:
372: synchronized (DEFAULT_SSL_PORT) {
373: String h = req.getHost();
374: if (h != null) {
375: StringTokenizer st = new StringTokenizer(h, ".");
376: int tokenCount = st.countTokens();
377: if (tokenCount == 1) {
378: currentReqHost = h + "." + rpSubdomain + rpDomain;
379: } else if (tokenCount == 2) {
380: currentReqHost = h + rpDomain;
381: } else {
382: currentReqHost = h;
383: }
384: } else {
385: currentReqHost = null;
386: }
387: try {
388: s.getOutputStream().write(new byte[0]);
389: } catch (IOException ex) {
390: currentReqHost = null;
391: throw ex;
392: }
393: currentReqHost = null;
394: }
395: }
396: }
|