7e6c813d1857df48e764d6803e64404261b5b827
[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 import eu.alefzero.owncloud.ui.activity.AuthenticatorActivity;
70
71
72 import android.content.Context;
73 import android.os.Handler;
74 import android.util.Log;
75
76 public class AuthUtils {
77 public static final String WEBDAV_PATH_1_2 = "/webdav/owncloud.php";
78 public static final String WEBDAV_PATH_2_0 = "/files/webdav.php";
79 public static final String CARDDAV_PATH_2_0 = "/apps/contacts/carddav.php";
80
81 private static String mResultMsg = "";
82
83 public static boolean authenticate(URL url, String username, String password,
84 Handler handler, Context context) {
85 String strippedPath = url.toString().endsWith("/") ?
86 url.toString().substring(0, url.toString().length()-1) :
87 url.toString();
88 String webdatPath = strippedPath + WEBDAV_PATH_2_0;
89 URL complete_url = null;
90 try {
91 complete_url = new URL(webdatPath);
92 } catch (MalformedURLException e) {
93 // should never happend
94 sendResult(false, handler, context, "URL error");
95 return false;
96 }
97
98 // version 2.0 success
99 if (tryGetWebdav(complete_url, username, password, handler, context)) {
100 sendResult(true, handler, context, complete_url.toString());
101 return true;
102 }
103
104 if (mResultMsg.equals("401")) {
105 sendResult(false, handler, context, "Invalid login or/and password");
106 return false;
107 }
108
109 if (!mResultMsg.equals("404")) {
110 sendResult(false, handler, context, "Server error: " + mResultMsg);
111 return false;
112 }
113
114 webdatPath = strippedPath + WEBDAV_PATH_1_2;
115 try {
116 complete_url = new URL(webdatPath);
117 } catch (MalformedURLException e) {
118 // should never happend
119 sendResult(false, handler, context, "URL error");
120 return false;
121 }
122
123 // version 1.2 success
124 if (tryGetWebdav(complete_url, username, password, handler, context)) {
125 sendResult(true, handler, context, complete_url.toString());
126 return true;
127 }
128
129 if (mResultMsg.equals("401")) {
130 sendResult(false, handler, context, "Invalid login or/and password");
131 return false;
132 }
133
134 if (mResultMsg.equals("404")) {
135 sendResult(false, handler, context, "Wrong path given");
136 return false;
137 }
138
139 sendResult(false, handler, context, "Server error: " + mResultMsg);
140 return false;
141 }
142
143 public static boolean tryGetWebdav(URL url, String username, String pwd,
144 Handler handler, Context context) {
145 SchemeRegistry schemeRegistry = new SchemeRegistry();
146 // http scheme
147 schemeRegistry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80));
148 // https scheme
149 schemeRegistry.register(new Scheme("https", new EasySSLSocketFactory(), 443));
150
151 HttpParams params = new BasicHttpParams();
152 params.setParameter(ConnManagerPNames.MAX_TOTAL_CONNECTIONS, 30);
153 params.setParameter(ConnManagerPNames.MAX_CONNECTIONS_PER_ROUTE, new ConnPerRouteBean(30));
154 params.setParameter(HttpProtocolParams.USE_EXPECT_CONTINUE, false);
155 HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1);
156
157 ClientConnectionManager cm = new ThreadSafeClientConnManager(params, schemeRegistry);
158
159 DefaultHttpClient c = new DefaultHttpClient(cm, params);
160
161 c.getCredentialsProvider().setCredentials(
162 new AuthScope(url.getHost(), (url.getPort() == -1)?80:url.getPort()),
163 new UsernamePasswordCredentials(username, pwd));
164
165 BasicHttpContext localcontext = new BasicHttpContext();
166 BasicScheme basicAuth = new BasicScheme();
167
168 localcontext.setAttribute("preemptive-auth", basicAuth);
169 HttpHost targetHost = new HttpHost(url.getHost(), (url.getPort() == -1)
170 ? 80
171 : url.getPort(), (url.getProtocol().equals("https")) ? "https" : "http");
172 HttpHead httpget = new HttpHead(url.toString());
173 httpget.setHeader("Host", url.getHost());
174 HttpResponse response = null;
175 try {
176 response = c.execute(targetHost, httpget, localcontext);
177 } catch (ClientProtocolException e1) {
178 sendResult(false, handler, context, "Protocol error: "
179 + e1.getLocalizedMessage());
180 return false;
181 } catch (UnknownHostException e1) {
182 mResultMsg = "Unknowh host: " + e1.getLocalizedMessage();
183 return false;
184 } catch (IOException e1) {
185 mResultMsg = "Error: " + e1.getLocalizedMessage();
186 return false;
187 }
188 String status = response.getStatusLine().toString();
189
190 status = status.split(" ")[1];
191 Log.i("AuthUtils", "Status returned: " + status);
192 if (status.equals("200")) {
193 return true;
194 } else if (status.equals("404")) {
195 mResultMsg = "404";
196 return false;
197 } else if (status.equals("401")) {
198 mResultMsg = "401";
199 return false;
200 }
201 mResultMsg = status;
202 return false;
203 }
204
205 public static Thread performOnBackgroundThread(final Runnable r) {
206 final Thread t = new Thread() {
207 @Override
208 public void run() {
209 try {
210 r.run();
211 } finally {}
212 }
213 };
214 t.start();
215 return t;
216 }
217
218 public static void sendResult(final Boolean result,
219 final Handler handler,
220 final Context context,
221 final String message) {
222 if (handler == null || context == null) {
223 return;
224 }
225 handler.post(new Runnable() {
226 public void run() {
227 ((AuthenticatorActivity) context).onAuthenticationResult(result, message);
228 }
229 });
230 }
231
232 public static Thread attemptAuth(final URL url, final String username,
233 final String password, final Handler handler,
234 final Context context) {
235 final Runnable r = new Runnable() {
236
237 public void run() {
238 authenticate(url, username, password, handler, context);
239 }
240 };
241 return performOnBackgroundThread(r);
242 }
243 }