SSL connections update: notice about untrusted certificates and allow the user save...
[pub/Android/ownCloud.git] / src / com / owncloud / android / network / AdvancedSslSocketFactory.java
1 /* ownCloud Android client application
2 * Copyright (C) 2012 Bartek Przybylski
3 *
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 3 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <http://www.gnu.org/licenses/>.
16 *
17 */
18
19 package com.owncloud.android.network;
20
21 import java.io.IOException;
22 import java.net.InetAddress;
23 import java.net.InetSocketAddress;
24 import java.net.Socket;
25 import java.net.SocketAddress;
26 import java.net.UnknownHostException;
27
28 import javax.net.SocketFactory;
29 import javax.net.ssl.SSLContext;
30 import javax.net.ssl.SSLSocket;
31
32 import org.apache.commons.httpclient.ConnectTimeoutException;
33 import org.apache.commons.httpclient.params.HttpConnectionParams;
34 import org.apache.commons.httpclient.protocol.ProtocolSocketFactory;
35 import org.apache.commons.httpclient.protocol.SecureProtocolSocketFactory;
36 import org.apache.http.conn.ssl.X509HostnameVerifier;
37
38 import android.util.Log;
39
40 /**
41 * AdvancedSSLProtocolSocketFactory allows to create SSL {@link Socket}s with
42 * a custom SSLContext and an optional Hostname Verifier.
43 *
44 * @author David A. Velasco
45 */
46
47 public class AdvancedSslSocketFactory implements ProtocolSocketFactory {
48
49 private static final String TAG = AdvancedSslSocketFactory.class.getSimpleName();
50
51 private SSLContext mSslContext = null;
52 private X509HostnameVerifier mHostnameVerifier;
53
54 /**
55 * Constructor for AdvancedSSLProtocolSocketFactory.
56 */
57 public AdvancedSslSocketFactory(SSLContext sslContext, X509HostnameVerifier hostnameVerifier) {
58 if (sslContext == null)
59 throw new IllegalArgumentException("AdvancedSslSocketFactory can not be created with a null SSLContext");
60 mSslContext = sslContext;
61 mHostnameVerifier = hostnameVerifier;
62 }
63
64 /**
65 * @see SecureProtocolSocketFactory#createSocket(java.lang.String,int,java.net.InetAddress,int)
66 */
67 public Socket createSocket(String host, int port, InetAddress clientHost, int clientPort) throws IOException, UnknownHostException {
68 Socket socket = mSslContext.getSocketFactory().createSocket(host, port, clientHost, clientPort);
69 verifyHostname(host, socket);
70 return socket;
71 }
72
73
74 /**
75 * Attempts to get a new socket connection to the given host within the
76 * given time limit.
77 *
78 * @param host the host name/IP
79 * @param port the port on the host
80 * @param clientHost the local host name/IP to bind the socket to
81 * @param clientPort the port on the local machine
82 * @param params {@link HttpConnectionParams Http connection parameters}
83 *
84 * @return Socket a new socket
85 *
86 * @throws IOException if an I/O error occurs while creating the socket
87 * @throws UnknownHostException if the IP address of the host cannot be
88 * determined
89 */
90 public Socket createSocket(final String host, final int port,
91 final InetAddress localAddress, final int localPort,
92 final HttpConnectionParams params) throws IOException,
93 UnknownHostException, ConnectTimeoutException {
94 Log.d(TAG, "Creating SSL Socket with remote " + host + ":" + port + ", local " + localAddress + ":" + localPort + ", params: " + params);
95 if (params == null) {
96 throw new IllegalArgumentException("Parameters may not be null");
97 }
98 int timeout = params.getConnectionTimeout();
99 SocketFactory socketfactory = mSslContext.getSocketFactory();
100 Log.d(TAG, " ... with connection timeout " + timeout + " and socket timeout " + params.getSoTimeout());
101 Socket socket = socketfactory.createSocket();
102 SocketAddress localaddr = new InetSocketAddress(localAddress, localPort);
103 SocketAddress remoteaddr = new InetSocketAddress(host, port);
104 socket.setSoTimeout(params.getSoTimeout());
105 socket.bind(localaddr);
106 socket.connect(remoteaddr, timeout);
107 verifyHostname(host, socket);
108 return socket;
109 }
110
111 /**
112 * @see SecureProtocolSocketFactory#createSocket(java.lang.String,int)
113 */
114 public Socket createSocket(String host, int port) throws IOException,
115 UnknownHostException {
116 Log.d(TAG, "Creating SSL Socket with remote " + host + ":" + port);
117 Socket socket = mSslContext.getSocketFactory().createSocket(host, port);
118 verifyHostname(host, socket);
119 return socket;
120 }
121
122 /**
123 * @see SecureProtocolSocketFactory#createSocket(java.net.Socket,java.lang.String,int,boolean)
124 */
125 /*public Socket createSocket(Socket socket, String host, int port,
126 boolean autoClose) throws IOException, UnknownHostException {
127 Log.d(TAG, "Creating SSL Socket from other shocket " + socket + " to remote " + host + ":" + port);
128 return getSSLContext().getSocketFactory().createSocket(socket, host,
129 port, autoClose);
130 }*/
131
132 public boolean equals(Object obj) {
133 return ((obj != null) && obj.getClass().equals(
134 AdvancedSslSocketFactory.class));
135 }
136
137 public int hashCode() {
138 return AdvancedSslSocketFactory.class.hashCode();
139 }
140
141
142 public X509HostnameVerifier getHostNameVerifier() {
143 return mHostnameVerifier;
144 }
145
146
147 public void setHostNameVerifier(X509HostnameVerifier hostnameVerifier) {
148 mHostnameVerifier = hostnameVerifier;
149 }
150
151 /**
152 * Verifies the host name with the content of the server certificate using the current host name verifier, if some
153 * @param socket
154 */
155 private void verifyHostname(String host, Socket socket) throws IOException {
156 if (mHostnameVerifier != null) {
157 try {
158 mHostnameVerifier.verify(host, (SSLSocket) socket);
159 } catch (IOException iox) {
160 try {
161 socket.close();
162 } catch (Exception x) {}
163 throw iox;
164 }
165 }
166 }
167
168 }