https for unsigned certificates in logging and uploading
[pub/Android/ownCloud.git] / src / eu / alefzero / owncloud / authenticator / AuthUtils.java
1 /* ownCloud Android client application
2 * Copyright (C) 2011 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 eu.alefzero.owncloud.authenticator;
20
21 import java.io.IOException;
22 import java.net.MalformedURLException;
23 import java.net.URL;
24 import java.net.UnknownHostException;
25 import java.security.KeyManagementException;
26 import java.security.KeyStore;
27 import java.security.KeyStoreException;
28 import java.security.NoSuchAlgorithmException;
29 import java.security.SecureRandom;
30 import java.security.UnrecoverableKeyException;
31
32 import javax.net.SocketFactory;
33 import javax.net.ssl.HostnameVerifier;
34 import javax.net.ssl.HttpsURLConnection;
35 import javax.net.ssl.SSLContext;
36 import javax.net.ssl.SSLSession;
37 import javax.net.ssl.TrustManager;
38 import javax.net.ssl.X509TrustManager;
39
40 import javax.security.cert.CertificateException;
41 import javax.security.cert.X509Certificate;
42
43 import org.apache.http.client.HttpClient;
44 import org.apache.http.conn.ClientConnectionManager;
45 import org.apache.http.conn.scheme.Scheme;
46 import org.apache.http.conn.scheme.SchemeRegistry;
47
48 import org.apache.http.impl.client.DefaultHttpClient;
49
50 import org.apache.commons.httpclient.auth.BasicScheme;
51 import org.apache.http.HttpHost;
52 import org.apache.http.HttpResponse;
53 import org.apache.http.HttpVersion;
54 import org.apache.http.auth.AuthScope;
55 import org.apache.http.auth.UsernamePasswordCredentials;
56 import org.apache.http.client.ClientProtocolException;
57 import org.apache.http.client.methods.HttpHead;
58 import org.apache.http.conn.params.ConnManagerPNames;
59 import org.apache.http.conn.params.ConnPerRouteBean;
60 import org.apache.http.conn.scheme.PlainSocketFactory;
61 import org.apache.http.conn.ssl.SSLSocketFactory;
62 import org.apache.http.impl.conn.SingleClientConnManager;
63 import org.apache.http.impl.conn.tsccm.ThreadSafeClientConnManager;
64 import org.apache.http.params.BasicHttpParams;
65 import org.apache.http.params.HttpParams;
66 import org.apache.http.params.HttpProtocolParams;
67 import org.apache.http.protocol.BasicHttpContext;
68
69
70 import android.content.Context;
71 import android.os.Handler;
72 import android.util.Log;
73
74 public class AuthUtils {
75 public static final String WEBDAV_PATH_1_2 = "/webdav/owncloud.php";
76 public static final String WEBDAV_PATH_2_0 = "/files/webdav.php";
77 public static final String CARDDAV_PATH_2_0 = "/apps/contacts/carddav.php";
78
79 private static String mResultMsg = "";
80
81 public static boolean authenticate(URL url, String username, String password,
82 Handler handler, Context context) {
83 String strippedPath = url.toString().endsWith("/") ?
84 url.toString().substring(0, url.toString().length()-1) :
85 url.toString();
86 String webdatPath = strippedPath + WEBDAV_PATH_2_0;
87 URL complete_url = null;
88 try {
89 complete_url = new URL(webdatPath);
90 } catch (MalformedURLException e) {
91 // should never happend
92 sendResult(false, handler, context, "URL error");
93 return false;
94 }
95
96 // version 2.0 success
97 if (tryGetWebdav(complete_url, username, password, handler, context)) {
98 sendResult(true, handler, context, complete_url.toString());
99 return true;
100 }
101
102 if (mResultMsg.equals("401")) {
103 sendResult(false, handler, context, "Invalid login or/and password");
104 return false;
105 }
106
107 if (!mResultMsg.equals("404")) {
108 sendResult(false, handler, context, "Server error: " + mResultMsg);
109 return false;
110 }
111
112 webdatPath = strippedPath + WEBDAV_PATH_1_2;
113 try {
114 complete_url = new URL(webdatPath);
115 } catch (MalformedURLException e) {
116 // should never happend
117 sendResult(false, handler, context, "URL error");
118 return false;
119 }
120
121 // version 1.2 success
122 if (tryGetWebdav(complete_url, username, password, handler, context)) {
123 sendResult(true, handler, context, complete_url.toString());
124 return true;
125 }
126
127 if (mResultMsg.equals("401")) {
128 sendResult(false, handler, context, "Invalid login or/and password");
129 return false;
130 }
131
132 if (mResultMsg.equals("404")) {
133 sendResult(false, handler, context, "Wrong path given");
134 return false;
135 }
136
137 sendResult(false, handler, context, "Server error: " + mResultMsg);
138 return false;
139 }
140
141 public static boolean tryGetWebdav(URL url, String username, String pwd,
142 Handler handler, Context context) {
143 SchemeRegistry schemeRegistry = new SchemeRegistry();
144 // http scheme
145 schemeRegistry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80));
146 // https scheme
147 schemeRegistry.register(new Scheme("https", new EasySSLSocketFactory(), 443));
148
149 HttpParams params = new BasicHttpParams();
150 params.setParameter(ConnManagerPNames.MAX_TOTAL_CONNECTIONS, 30);
151 params.setParameter(ConnManagerPNames.MAX_CONNECTIONS_PER_ROUTE, new ConnPerRouteBean(30));
152 params.setParameter(HttpProtocolParams.USE_EXPECT_CONTINUE, false);
153 HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1);
154
155 ClientConnectionManager cm = new ThreadSafeClientConnManager(params, schemeRegistry);
156
157 DefaultHttpClient c = new DefaultHttpClient(cm, params);
158
159 c.getCredentialsProvider().setCredentials(
160 new AuthScope(url.getHost(), (url.getPort() == -1)?80:url.getPort()),
161 new UsernamePasswordCredentials(username, pwd));
162
163 BasicHttpContext localcontext = new BasicHttpContext();
164 BasicScheme basicAuth = new BasicScheme();
165
166 localcontext.setAttribute("preemptive-auth", basicAuth);
167 HttpHost targetHost = new HttpHost(url.getHost(), (url.getPort() == -1)
168 ? 80
169 : url.getPort(), (url.getProtocol().equals("https")) ? "https" : "http");
170 HttpHead httpget = new HttpHead(url.toString());
171 httpget.setHeader("Host", url.getHost());
172 HttpResponse response = null;
173 try {
174 response = c.execute(targetHost, httpget, localcontext);
175 } catch (ClientProtocolException e1) {
176 sendResult(false, handler, context, "Protocol error: "
177 + e1.getLocalizedMessage());
178 return false;
179 } catch (UnknownHostException e1) {
180 mResultMsg = "Unknowh host: " + e1.getLocalizedMessage();
181 return false;
182 } catch (IOException e1) {
183 mResultMsg = "Error: " + e1.getLocalizedMessage();
184 return false;
185 }
186 String status = response.getStatusLine().toString();
187
188 status = status.split(" ")[1];
189 Log.i("AuthUtils", "Status returned: " + status);
190 if (status.equals("200")) {
191 return true;
192 } else if (status.equals("404")) {
193 mResultMsg = "404";
194 return false;
195 } else if (status.equals("401")) {
196 mResultMsg = "401";
197 return false;
198 }
199 mResultMsg = status;
200 return false;
201 }
202
203 public static Thread performOnBackgroundThread(final Runnable r) {
204 final Thread t = new Thread() {
205 @Override
206 public void run() {
207 try {
208 r.run();
209 } finally {}
210 }
211 };
212 t.start();
213 return t;
214 }
215
216 public static void sendResult(final Boolean result,
217 final Handler handler,
218 final Context context,
219 final String message) {
220 if (handler == null || context == null) {
221 return;
222 }
223 handler.post(new Runnable() {
224 public void run() {
225 ((AuthenticatorActivity) context).onAuthenticationResult(result, message);
226 }
227 });
228 }
229
230 public static Thread attemptAuth(final URL url, final String username,
231 final String password, final Handler handler,
232 final Context context) {
233 final Runnable r = new Runnable() {
234
235 public void run() {
236 authenticate(url, username, password, handler, context);
237 }
238 };
239 return performOnBackgroundThread(r);
240 }
241 }