SsoWebViewClient.java 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195
  1. /**
  2. * ownCloud Android client application
  3. *
  4. * @author David A. Velasco
  5. * Copyright (C) 2015 ownCloud Inc.
  6. *
  7. * This program is free software: you can redistribute it and/or modify
  8. * it under the terms of the GNU General Public License version 2,
  9. * as published by the Free Software Foundation.
  10. *
  11. * This program is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU General Public License
  17. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  18. *
  19. */
  20. package com.owncloud.android.authentication;
  21. import android.content.Context;
  22. import android.graphics.Bitmap;
  23. import android.net.http.SslCertificate;
  24. import android.net.http.SslError;
  25. import android.os.Bundle;
  26. import android.os.Handler;
  27. import android.os.Message;
  28. import android.view.View;
  29. import android.webkit.CookieManager;
  30. import android.webkit.HttpAuthHandler;
  31. import android.webkit.SslErrorHandler;
  32. import android.webkit.WebView;
  33. import android.webkit.WebViewClient;
  34. import com.owncloud.android.lib.common.network.NetworkUtils;
  35. import com.owncloud.android.lib.common.utils.Log_OC;
  36. import java.io.ByteArrayInputStream;
  37. import java.lang.ref.WeakReference;
  38. import java.security.cert.Certificate;
  39. import java.security.cert.CertificateException;
  40. import java.security.cert.CertificateFactory;
  41. import java.security.cert.X509Certificate;
  42. /**
  43. * Custom {@link WebViewClient} client aimed to catch the end of a single-sign-on process
  44. * running in the {@link WebView} that is attached to.
  45. *
  46. * Assumes that the single-sign-on is kept thanks to a cookie set at the end of the
  47. * authentication process.
  48. */
  49. public class SsoWebViewClient extends WebViewClient {
  50. private static final String TAG = SsoWebViewClient.class.getSimpleName();
  51. public interface SsoWebViewClientListener {
  52. public void onSsoFinished(String sessionCookie);
  53. }
  54. private Context mContext;
  55. private Handler mListenerHandler;
  56. private WeakReference<SsoWebViewClientListener> mListenerRef;
  57. private String mTargetUrl;
  58. private String mLastReloadedUrlAtError;
  59. public SsoWebViewClient (Context context, Handler listenerHandler, SsoWebViewClientListener listener) {
  60. mContext = context;
  61. mListenerHandler = listenerHandler;
  62. mListenerRef = new WeakReference<SsoWebViewClient.SsoWebViewClientListener>(listener);
  63. mTargetUrl = "fake://url.to.be.set";
  64. mLastReloadedUrlAtError = null;
  65. }
  66. public String getTargetUrl() {
  67. return mTargetUrl;
  68. }
  69. public void setTargetUrl(String targetUrl) {
  70. mTargetUrl = targetUrl;
  71. }
  72. @Override
  73. public void onPageStarted (WebView view, String url, Bitmap favicon) {
  74. Log_OC.d(TAG, "onPageStarted : " + url);
  75. view.clearCache(true);
  76. super.onPageStarted(view, url, favicon);
  77. }
  78. @Override
  79. public void onFormResubmission (WebView view, Message dontResend, Message resend) {
  80. Log_OC.d(TAG, "onFormResubMission ");
  81. // necessary to grant reload of last page when device orientation is changed after sending a form
  82. resend.sendToTarget();
  83. }
  84. @Override
  85. public boolean shouldOverrideUrlLoading(WebView view, String url) {
  86. return false;
  87. }
  88. @Override
  89. public void onReceivedError (WebView view, int errorCode, String description, String failingUrl) {
  90. Log_OC.e(TAG, "onReceivedError : " + failingUrl + ", code " + errorCode + ", description: " + description);
  91. if (!failingUrl.equals(mLastReloadedUrlAtError)) {
  92. view.reload();
  93. mLastReloadedUrlAtError = failingUrl;
  94. } else {
  95. mLastReloadedUrlAtError = null;
  96. super.onReceivedError(view, errorCode, description, failingUrl);
  97. }
  98. }
  99. @Override
  100. public void onPageFinished (WebView view, String url) {
  101. Log_OC.d(TAG, "onPageFinished : " + url);
  102. mLastReloadedUrlAtError = null;
  103. if (url.startsWith(mTargetUrl)) {
  104. view.setVisibility(View.GONE);
  105. CookieManager cookieManager = CookieManager.getInstance();
  106. final String cookies = cookieManager.getCookie(url);
  107. //Log_OC.d(TAG, "Cookies: " + cookies);
  108. if (mListenerHandler != null && mListenerRef != null) {
  109. // this is good idea because onPageFinished is not running in the UI thread
  110. mListenerHandler.post(new Runnable() {
  111. @Override
  112. public void run() {
  113. SsoWebViewClientListener listener = mListenerRef.get();
  114. if (listener != null) {
  115. // Send Cookies to the listener
  116. listener.onSsoFinished(cookies);
  117. }
  118. }
  119. });
  120. }
  121. }
  122. }
  123. @Override
  124. public void onReceivedSslError (final WebView view, final SslErrorHandler handler, SslError error) {
  125. Log_OC.e(TAG, "onReceivedSslError : " + error);
  126. // Test 1
  127. X509Certificate x509Certificate = getX509CertificateFromError(error);
  128. boolean isKnownServer = false;
  129. if (x509Certificate != null) {
  130. try {
  131. isKnownServer = NetworkUtils.isCertInKnownServersStore((Certificate) x509Certificate, mContext);
  132. } catch (Exception e) {
  133. Log_OC.e(TAG, "Exception: " + e.getMessage());
  134. }
  135. }
  136. if (isKnownServer) {
  137. handler.proceed();
  138. } else {
  139. ((AuthenticatorActivity)mContext).showUntrustedCertDialog(x509Certificate, error, handler);
  140. }
  141. }
  142. /**
  143. * Obtain the X509Certificate from SslError
  144. * @param error SslError
  145. * @return X509Certificate from error
  146. */
  147. public X509Certificate getX509CertificateFromError (SslError error) {
  148. Bundle bundle = SslCertificate.saveState(error.getCertificate());
  149. X509Certificate x509Certificate;
  150. byte[] bytes = bundle.getByteArray("x509-certificate");
  151. if (bytes == null) {
  152. x509Certificate = null;
  153. } else {
  154. try {
  155. CertificateFactory certFactory = CertificateFactory.getInstance("X.509");
  156. Certificate cert = certFactory.generateCertificate(new ByteArrayInputStream(bytes));
  157. x509Certificate = (X509Certificate) cert;
  158. } catch (CertificateException e) {
  159. x509Certificate = null;
  160. }
  161. }
  162. return x509Certificate;
  163. }
  164. @Override
  165. public void onReceivedHttpAuthRequest (WebView view, HttpAuthHandler handler, String host, String realm) {
  166. Log_OC.d(TAG, "onReceivedHttpAuthRequest : " + host);
  167. ((AuthenticatorActivity)mContext).createAuthenticationDialog(view, handler);
  168. }
  169. }