001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */
017:
018: package org.apache.jmeter.util;
019:
020: import java.io.IOException;
021: import java.net.InetAddress;
022: import java.net.InetSocketAddress;
023: import java.net.Socket;
024: import java.net.SocketAddress;
025: import java.net.UnknownHostException;
026: import java.security.GeneralSecurityException;
027:
028: import javax.net.ssl.SSLContext;
029: import javax.net.ssl.SSLSession;
030: import javax.net.ssl.SSLSocket;
031: import javax.net.ssl.SSLSocketFactory;
032:
033: import org.apache.commons.httpclient.ConnectTimeoutException;
034: import org.apache.commons.httpclient.params.HttpConnectionParams;
035: import org.apache.commons.httpclient.protocol.SecureProtocolSocketFactory;
036: import org.apache.jorphan.logging.LoggingManager;
037: import org.apache.log.Logger;
038:
039: /**
040: * Derived from EasySSLProtocolFactory
041: *
042: * Used by JsseSSLManager to set up the HttpClient and Java https socket handling
043: */
044:
045: public class HttpSSLProtocolSocketFactory extends SSLSocketFactory // for java sockets
046: implements SecureProtocolSocketFactory { // for httpclient sockets
047:
048: private static final Logger log = LoggingManager
049: .getLoggerForClass();
050:
051: private JsseSSLManager sslManager;
052:
053: private final int CPS; // Characters per second to emulate
054:
055: private HttpSSLProtocolSocketFactory() {
056: CPS = 0;
057: }
058:
059: public HttpSSLProtocolSocketFactory(JsseSSLManager sslManager) {
060: super ();
061: this .sslManager = sslManager;
062: CPS = 0;
063: }
064:
065: public HttpSSLProtocolSocketFactory(JsseSSLManager sslManager,
066: int cps) {
067: super ();
068: this .sslManager = sslManager;
069: CPS = cps;
070: }
071:
072: private static final String protocolList = JMeterUtils
073: .getPropDefault("https.socket.protocols", ""); // $NON-NLS-1$ $NON-NLS-2$
074:
075: static {
076: if (protocolList.length() > 0) {
077: log.info("Using protocol list: " + protocolList);
078: }
079: }
080:
081: private static final String[] protocols = protocolList.split(" "); // $NON-NLS-1$
082:
083: private void setSocket(Socket socket) {
084: if (!(socket instanceof SSLSocket)) {
085: throw new IllegalArgumentException("Expected SSLSocket");
086: }
087: SSLSocket sock = (SSLSocket) socket;
088: if (log.isDebugEnabled()) {
089: /* Warning: the next line seems to cause the error
090: * javax.net.ssl.SSLException: Received fatal alert: unexpected_message
091: * with certain sites
092: */
093: SSLSession sslSession = sock.getSession();
094: byte[] bytes = sslSession.getId();
095:
096: StringBuffer buffer = new StringBuffer("SSL session id: ");
097: for (int i = 0; i < bytes.length; i++) {
098: int b = bytes[i] & 0xff;
099: buffer.append(Character.toUpperCase(Character.forDigit(
100: (b >> 4) & 0xF, 16)));
101: buffer.append(Character.toUpperCase(Character.forDigit(
102: b & 0xF, 16)));
103: }
104: buffer.append(" for ").append(
105: Thread.currentThread().getName());
106: log.debug(buffer.toString());
107: }
108: if (protocolList.length() > 0) {
109: try {
110: sock.setEnabledProtocols(protocols);
111: } catch (IllegalArgumentException e) {
112: log.warn("Could not set protocol list: " + protocolList
113: + ".");
114: log.warn("Valid protocols are: "
115: + join(sock.getSupportedProtocols()));
116: }
117: }
118: }
119:
120: private String join(String[] strings) {
121: StringBuffer sb = new StringBuffer();
122: for (int i = 0; i < strings.length; i++) {
123: if (i > 0)
124: sb.append(" ");
125: sb.append(strings[i]);
126: }
127: return sb.toString();
128: }
129:
130: private SSLSocketFactory getSSLSocketFactory() throws IOException {
131: try {
132: SSLContext sslContext = this .sslManager.getContext();
133: return sslContext.getSocketFactory();
134: } catch (GeneralSecurityException ex) {
135: throw new IOException(ex.getMessage());
136: }
137: }
138:
139: /*
140: * Wraps the socket in a slow SSL socket if necessary
141: */
142: private Socket wrapSocket(Socket sock) {
143: if (CPS > 0)
144: return new SlowSSLSocket((SSLSocket) sock, CPS);
145: return sock;
146: }
147:
148: /**
149: * Attempts to get a new socket connection to the given host within the given time limit.
150: *
151: * @param host the host name/IP
152: * @param port the port on the host
153: * @param localAddress the local host name/IP to bind the socket to
154: * @param localPort the port on the local machine
155: * @param params {@link HttpConnectionParams Http connection parameters}
156: *
157: * @return Socket a new socket
158: *
159: * @throws IOException if an I/O error occurs while creating the socket
160: * @throws UnknownHostException if the IP address of the host cannot be
161: * determined
162: */
163: public Socket createSocket(final String host, final int port,
164: final InetAddress localAddress, final int localPort,
165: final HttpConnectionParams params) throws IOException,
166: UnknownHostException, ConnectTimeoutException {
167: if (params == null) {
168: throw new IllegalArgumentException(
169: "Parameters may not be null");
170: }
171: int timeout = params.getConnectionTimeout();
172:
173: SSLSocketFactory sslfac = getSSLSocketFactory();
174: Socket socket;
175: if (timeout == 0) {
176: socket = sslfac.createSocket(host, port, localAddress,
177: localPort);
178: } else {
179: socket = sslfac.createSocket();
180: SocketAddress localaddr = new InetSocketAddress(
181: localAddress, localPort);
182: SocketAddress remoteaddr = new InetSocketAddress(host, port);
183: socket.bind(localaddr);
184: socket.connect(remoteaddr, timeout);
185: }
186: setSocket(socket);
187: return wrapSocket(socket);
188: }
189:
190: /**
191: * @see SecureProtocolSocketFactory#createSocket(java.lang.String,int)
192: */
193: public Socket createSocket(String host, int port)
194: throws IOException, UnknownHostException {
195: SSLSocketFactory sslfac = getSSLSocketFactory();
196: Socket sock = sslfac.createSocket(host, port);
197: setSocket(sock);
198: return wrapSocket(sock);
199: }
200:
201: /**
202: * @see SecureProtocolSocketFactory#createSocket(java.net.Socket,java.lang.String,int,boolean)
203: */
204: public Socket createSocket(Socket socket, String host, int port,
205: boolean autoClose) throws IOException, UnknownHostException {
206: SSLSocketFactory sslfac = getSSLSocketFactory();
207: Socket sock = sslfac
208: .createSocket(socket, host, port, autoClose);
209: setSocket(sock);
210: return wrapSocket(sock);
211: }
212:
213: /**
214: * @see SecureProtocolSocketFactory#createSocket(java.lang.String,int,java.net.InetAddress,int)
215: */
216: public Socket createSocket(String host, int port,
217: InetAddress clientHost, int clientPort) throws IOException,
218: UnknownHostException {
219:
220: SSLSocketFactory sslfac = getSSLSocketFactory();
221: Socket sock = sslfac.createSocket(host, port, clientHost,
222: clientPort);
223: setSocket(sock);
224: return wrapSocket(sock);
225: }
226:
227: public Socket createSocket(InetAddress host, int port)
228: throws IOException {
229: SSLSocketFactory sslfac = getSSLSocketFactory();
230: Socket sock = sslfac.createSocket(host, port);
231: setSocket(sock);
232: return wrapSocket(sock);
233: }
234:
235: public Socket createSocket(InetAddress address, int port,
236: InetAddress localAddress, int localPort) throws IOException {
237: SSLSocketFactory sslfac = getSSLSocketFactory();
238: Socket sock = sslfac.createSocket(address, port, localAddress,
239: localPort);
240: setSocket(sock);
241: return wrapSocket(sock);
242: }
243:
244: public String[] getDefaultCipherSuites() {
245: try {
246: SSLSocketFactory sslfac = getSSLSocketFactory();
247: return sslfac.getDefaultCipherSuites();
248: } catch (IOException ex) {
249: return new String[] {};
250: }
251: }
252:
253: public String[] getSupportedCipherSuites() {
254: try {
255: SSLSocketFactory sslfac = getSSLSocketFactory();
256: return sslfac.getSupportedCipherSuites();
257: } catch (IOException ex) {
258: return new String[] {};
259: }
260: }
261: }
|