Merge pull request #918 from owncloud/share_password_support
[pub/Android/ownCloud.git] / src / com / owncloud / android / authentication / SsoWebViewClient.java
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
21 package com.owncloud.android.authentication;
22
23 import java.io.ByteArrayInputStream;
24 import java.lang.ref.WeakReference;
25 import java.security.cert.Certificate;
26 import java.security.cert.CertificateException;
27 import java.security.cert.CertificateFactory;
28 import java.security.cert.X509Certificate;
29
30 import com.owncloud.android.lib.common.network.NetworkUtils;
31 import com.owncloud.android.lib.common.utils.Log_OC;
32
33 import android.content.Context;
34 import android.graphics.Bitmap;
35 import android.net.http.SslCertificate;
36 import android.net.http.SslError;
37 import android.os.Bundle;
38 import android.os.Handler;
39 import android.os.Message;
40 import android.view.KeyEvent;
41 import android.view.View;
42 import android.webkit.CookieManager;
43 import android.webkit.HttpAuthHandler;
44 import android.webkit.SslErrorHandler;
45 import android.webkit.WebResourceResponse;
46 import android.webkit.WebView;
47 import android.webkit.WebViewClient;
48
49
50 /**
51 * Custom {@link WebViewClient} client aimed to catch the end of a single-sign-on process
52 * running in the {@link WebView} that is attached to.
53 *
54 * Assumes that the single-sign-on is kept thanks to a cookie set at the end of the
55 * authentication process.
56 */
57 public class SsoWebViewClient extends WebViewClient {
58
59 private static final String TAG = SsoWebViewClient.class.getSimpleName();
60
61 public interface SsoWebViewClientListener {
62 public void onSsoFinished(String sessionCookie);
63 }
64
65 private Context mContext;
66 private Handler mListenerHandler;
67 private WeakReference<SsoWebViewClientListener> mListenerRef;
68 private String mTargetUrl;
69 private String mLastReloadedUrlAtError;
70
71
72 public SsoWebViewClient (Context context, Handler listenerHandler, SsoWebViewClientListener listener) {
73 mContext = context;
74 mListenerHandler = listenerHandler;
75 mListenerRef = new WeakReference<SsoWebViewClient.SsoWebViewClientListener>(listener);
76 mTargetUrl = "fake://url.to.be.set";
77 mLastReloadedUrlAtError = null;
78 }
79
80 public String getTargetUrl() {
81 return mTargetUrl;
82 }
83
84 public void setTargetUrl(String targetUrl) {
85 mTargetUrl = targetUrl;
86 }
87
88 @Override
89 public void onPageStarted (WebView view, String url, Bitmap favicon) {
90 Log_OC.d(TAG, "onPageStarted : " + url);
91 view.clearCache(true);
92 super.onPageStarted(view, url, favicon);
93 }
94
95 @Override
96 public void onFormResubmission (WebView view, Message dontResend, Message resend) {
97 Log_OC.d(TAG, "onFormResubMission ");
98
99 // necessary to grant reload of last page when device orientation is changed after sending a form
100 resend.sendToTarget();
101 }
102
103 @Override
104 public boolean shouldOverrideUrlLoading(WebView view, String url) {
105 return false;
106 }
107
108 @Override
109 public void onReceivedError (WebView view, int errorCode, String description, String failingUrl) {
110 Log_OC.e(TAG, "onReceivedError : " + failingUrl + ", code " + errorCode + ", description: " + description);
111 if (!failingUrl.equals(mLastReloadedUrlAtError)) {
112 view.reload();
113 mLastReloadedUrlAtError = failingUrl;
114 } else {
115 mLastReloadedUrlAtError = null;
116 super.onReceivedError(view, errorCode, description, failingUrl);
117 }
118 }
119
120 @Override
121 public void onPageFinished (WebView view, String url) {
122 Log_OC.d(TAG, "onPageFinished : " + url);
123 mLastReloadedUrlAtError = null;
124 if (url.startsWith(mTargetUrl)) {
125 view.setVisibility(View.GONE);
126 CookieManager cookieManager = CookieManager.getInstance();
127 final String cookies = cookieManager.getCookie(url);
128 //Log_OC.d(TAG, "Cookies: " + cookies);
129 if (mListenerHandler != null && mListenerRef != null) {
130 // this is good idea because onPageFinished is not running in the UI thread
131 mListenerHandler.post(new Runnable() {
132 @Override
133 public void run() {
134 SsoWebViewClientListener listener = mListenerRef.get();
135 if (listener != null) {
136 // Send Cookies to the listener
137 listener.onSsoFinished(cookies);
138 }
139 }
140 });
141 }
142 }
143 }
144
145 @Override
146 public void onReceivedSslError (final WebView view, final SslErrorHandler handler, SslError error) {
147 Log_OC.e(TAG, "onReceivedSslError : " + error);
148 // Test 1
149 X509Certificate x509Certificate = getX509CertificateFromError(error);
150 boolean isKnownServer = false;
151
152 if (x509Certificate != null) {
153 try {
154 isKnownServer = NetworkUtils.isCertInKnownServersStore((Certificate) x509Certificate, mContext);
155 } catch (Exception e) {
156 Log_OC.e(TAG, "Exception: " + e.getMessage());
157 }
158 }
159
160 if (isKnownServer) {
161 handler.proceed();
162 } else {
163 ((AuthenticatorActivity)mContext).showUntrustedCertDialog(x509Certificate, error, handler);
164 }
165 }
166
167 /**
168 * Obtain the X509Certificate from SslError
169 * @param error SslError
170 * @return X509Certificate from error
171 */
172 public X509Certificate getX509CertificateFromError (SslError error) {
173 Bundle bundle = SslCertificate.saveState(error.getCertificate());
174 X509Certificate x509Certificate;
175 byte[] bytes = bundle.getByteArray("x509-certificate");
176 if (bytes == null) {
177 x509Certificate = null;
178 } else {
179 try {
180 CertificateFactory certFactory = CertificateFactory.getInstance("X.509");
181 Certificate cert = certFactory.generateCertificate(new ByteArrayInputStream(bytes));
182 x509Certificate = (X509Certificate) cert;
183 } catch (CertificateException e) {
184 x509Certificate = null;
185 }
186 }
187 return x509Certificate;
188 }
189
190 @Override
191 public void onReceivedHttpAuthRequest (WebView view, HttpAuthHandler handler, String host, String realm) {
192 Log_OC.d(TAG, "onReceivedHttpAuthRequest : " + host);
193
194 ((AuthenticatorActivity)mContext).createAuthenticationDialog(view, handler);
195 }
196
197 }