1 /* ownCloud Android client application 
   2  *   Copyright (C) 2011  Bartek Przybylski 
   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. 
   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. 
  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/>. 
  19 package eu
.alefzero
.owncloud
.authenticator
; 
  21 import java
.io
.IOException
; 
  22 import java
.net
.MalformedURLException
; 
  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
; 
  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
; 
  40 import javax
.security
.cert
.CertificateException
; 
  41 import javax
.security
.cert
.X509Certificate
; 
  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
; 
  48 import org
.apache
.http
.impl
.client
.DefaultHttpClient
; 
  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
; 
  70 import android
.content
.Context
; 
  71 import android
.os
.Handler
; 
  72 import android
.util
.Log
; 
  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"; 
  79   private static String mResultMsg 
= ""; 
  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) : 
  86     String webdatPath 
= strippedPath 
+ WEBDAV_PATH_2_0
; 
  87     URL complete_url 
= null
; 
  89       complete_url 
= new URL(webdatPath
); 
  90     } catch (MalformedURLException e
) { 
  91       // should never happend 
  92       sendResult(false
, handler
, context
, "URL error"); 
  96     // version 2.0 success 
  97     if (tryGetWebdav(complete_url
, username
, password
, handler
, context
)) { 
  98       sendResult(true
, handler
, context
, complete_url
.toString()); 
 102     if (mResultMsg
.equals("401")) { 
 103        sendResult(false
, handler
, context
, "Invalid login or/and password"); 
 107     if (!mResultMsg
.equals("404")) { 
 108       sendResult(false
, handler
, context
, "Server error: " + mResultMsg
); 
 112     webdatPath 
= strippedPath 
+ WEBDAV_PATH_1_2
; 
 114       complete_url 
= new URL(webdatPath
); 
 115     } catch (MalformedURLException e
) { 
 116       // should never happend 
 117       sendResult(false
, handler
, context
, "URL error"); 
 121     // version 1.2 success 
 122     if (tryGetWebdav(complete_url
, username
, password
, handler
, context
)) { 
 123       sendResult(true
, handler
, context
, complete_url
.toString()); 
 127     if (mResultMsg
.equals("401")) { 
 128       sendResult(false
, handler
, context
, "Invalid login or/and password"); 
 132     if (mResultMsg
.equals("404")) { 
 133       sendResult(false
, handler
, context
, "Wrong path given"); 
 137     sendResult(false
, handler
, context
, "Server error: " + mResultMsg
); 
 141   public static boolean tryGetWebdav(URL url
, String username
, String pwd
, 
 142                                      Handler handler
, Context context
) { 
 143     SchemeRegistry schemeRegistry 
= new SchemeRegistry(); 
 145  schemeRegistry
.register(new Scheme("http", PlainSocketFactory
.getSocketFactory(), 80)); 
 147  schemeRegistry
.register(new Scheme("https", new EasySSLSocketFactory(), 443)); 
 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
); 
 155  ClientConnectionManager cm 
= new ThreadSafeClientConnManager(params
, schemeRegistry
); 
 157     DefaultHttpClient c 
= new DefaultHttpClient(cm
, params
); 
 159     c
.getCredentialsProvider().setCredentials( 
 160         new AuthScope(url
.getHost(), (url
.getPort() == -1)?
80:url
.getPort()),  
 161         new UsernamePasswordCredentials(username
, pwd
)); 
 163     BasicHttpContext localcontext  
= new BasicHttpContext(); 
 164     BasicScheme basicAuth 
= new BasicScheme(); 
 166     localcontext
.setAttribute("preemptive-auth", basicAuth
); 
 167     HttpHost targetHost 
= new HttpHost(url
.getHost(), (url
.getPort() == -1) 
 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
; 
 174       response 
= c
.execute(targetHost
, httpget
, localcontext
); 
 175     } catch (ClientProtocolException e1
) { 
 176       sendResult(false
, handler
, context
, "Protocol error: " 
 177           + e1
.getLocalizedMessage()); 
 179     } catch (UnknownHostException e1
) { 
 180       mResultMsg 
= "Unknowh host: " + e1
.getLocalizedMessage(); 
 182     } catch (IOException e1
) { 
 183       mResultMsg 
= "Error: " + e1
.getLocalizedMessage(); 
 186     String status 
= response
.getStatusLine().toString(); 
 188     status 
= status
.split(" ")[1]; 
 189     Log
.i("AuthUtils", "Status returned: " + status
); 
 190     if (status
.equals("200")) { 
 192     } else if (status
.equals("404")) { 
 195     } else if (status
.equals("401")) { 
 203   public static Thread 
performOnBackgroundThread(final Runnable r
) { 
 204     final Thread t 
= new Thread() { 
 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
) { 
 223     handler
.post(new Runnable() { 
 225         ((AuthenticatorActivity
) context
).onAuthenticationResult(result
, message
);  
 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() { 
 236         authenticate(url
, username
, password
, handler
, context
); 
 239     return performOnBackgroundThread(r
);