/* * Copyright 2001-2004 The Apache Software Foundation. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package eu.doppel_helix.netbeans.mantisintegration.axis; import org.apache.axis.utils.StringUtils; import javax.net.ssl.SSLSocket; import javax.net.ssl.SSLSocketFactory; import java.io.BufferedWriter; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.io.OutputStreamWriter; import java.io.PrintWriter; import java.net.InetSocketAddress; import java.net.Proxy; import java.net.ProxySelector; import java.net.Socket; import java.net.URI; import java.util.Hashtable; import java.util.List; import java.util.logging.Level; import java.util.logging.Logger; import org.apache.axis.components.net.BooleanHolder; import static org.apache.axis.components.net.DefaultSocketFactory.CONNECT_TIMEOUT; import org.apache.axis.components.net.SecureSocketFactory; /** * This is inspired by the JSSESocketFactory from the axis package */ public class NbSecureSocketFactory extends NbBaseSocketFactory implements SecureSocketFactory { private static final Logger LOG = Logger.getLogger(NbSocketFactory.class.getName()); /** * Field sslFactory */ protected SSLSocketFactory sslFactory = null; public NbSecureSocketFactory(Hashtable attributes) { super(attributes); } /** * Initialize the SSLSocketFactory * * @throws IOException */ protected void initFactory() throws IOException { sslFactory = (SSLSocketFactory) SSLSocketFactory.getDefault(); } @Override public Socket create(String host, int port, StringBuffer otherHeaders, BooleanHolder useFullURL) throws Exception { int timeout = 0; if (attributes != null) { String value = (String) attributes.get(CONNECT_TIMEOUT); timeout = (value != null) ? Integer.parseInt(value) : 0; } if (sslFactory == null) { initFactory(); } if (port == -1) { port = 443; } // Construct pseudo URL to determine proxy URI pseudoUri = new URI("https", null, host, port, null, null, null); List<Proxy> proxies = ProxySelector.getDefault().select(pseudoUri); Socket s = null; // If a direct connetion is possible - use it if (s == null) { for (Proxy p : proxies) { try { Socket baseSocket = null; if (null != p.type()) switch (p.type()) { case DIRECT: baseSocket = new Socket(); baseSocket.connect(new InetSocketAddress(host, port), timeout); break; case SOCKS: baseSocket = new Socket(p); baseSocket.connect(new InetSocketAddress(host, port), timeout); break; case HTTP: baseSocket = new Socket(); baseSocket.connect(p.address()); // The tunnel handshake method (condensed and made reflexive) OutputStream tunnelOutputStream = baseSocket.getOutputStream(); PrintWriter out = new PrintWriter( new BufferedWriter(new OutputStreamWriter(tunnelOutputStream))); out.print("CONNECT " + host + ":" + port + " HTTP/1.0\r\n" + "User-Agent: AxisClient"); String authorization = getAuthorizationHeader(); if (!authorization.isEmpty()) { out.write("\n"); out.write(authorization); } out.print("\nContent-Length: 0"); out.print("\nPragma: no-cache"); out.print("\r\n\r\n"); out.flush(); InputStream tunnelInputStream = baseSocket.getInputStream(); String replyStr = ""; // Make sure to read all the response from the proxy to prevent SSL negotiation failure // Response message terminated by two sequential newlines int newlinesSeen = 0; boolean headerDone = false; /* Done on first newline */ while (newlinesSeen < 2) { int i = tunnelInputStream.read(); if (i < 0) { throw new IOException("Unexpected EOF from proxy"); } if (i == '\n') { headerDone = true; ++newlinesSeen; } else if (i != '\r') { newlinesSeen = 0; if (!headerDone) { replyStr += String.valueOf((char) i); } } } if (!(StringUtils.startsWithIgnoreWhitespaces("HTTP/1.0 200", replyStr) || StringUtils.startsWithIgnoreWhitespaces("HTTP/1.1 200", replyStr))) { throw new IOException(); } break; default: } if (baseSocket != null) { // End of condensed reflective tunnel handshake method s = sslFactory.createSocket(baseSocket, host, port, true); ((SSLSocket) s).startHandshake(); break; } } catch (IOException | IllegalArgumentException ex) { LOG.log(Level.WARNING, "Failed proxy connection", ex); } } } return s; } }