Merge branch 'develop' into check_server_certificates_in_SSO_webview
[pub/Android/ownCloud.git] / src / com / owncloud / android / ui / dialog / SslUntrustedCertDialog.java
1 /* ownCloud Android client application
2 * Copyright (C) 2012-2014 ownCloud Inc.
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 version 2,
6 * as published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 *
16 */
17 package com.owncloud.android.ui.dialog;
18
19 import java.io.IOException;
20 import java.security.GeneralSecurityException;
21 import java.security.KeyStoreException;
22 import java.security.NoSuchAlgorithmException;
23 import java.security.cert.CertificateException;
24 import java.security.cert.X509Certificate;
25 import java.util.Date;
26 import java.util.HashMap;
27 import java.util.Map;
28
29 import javax.security.auth.x500.X500Principal;
30
31 import com.actionbarsherlock.app.SherlockDialogFragment;
32 import com.owncloud.android.R;
33 import com.owncloud.android.authentication.AuthenticatorActivity;
34 import com.owncloud.android.lib.common.network.NetworkUtils;
35 import com.owncloud.android.utils.Log_OC;
36
37 import android.app.Dialog;
38 import android.content.Context;
39 import android.os.Bundle;
40 import android.view.LayoutInflater;
41 import android.view.View;
42 import android.view.View.OnClickListener;
43 import android.view.ViewGroup;
44 import android.view.Window;
45 import android.webkit.SslErrorHandler;
46 import android.widget.Button;
47 import android.widget.TextView;
48
49 /**
50 * Dialog to show an Untrusted Certificate
51 *
52 * @author masensio
53 *
54 */
55 public class SslUntrustedCertDialog extends SherlockDialogFragment{
56
57 private final static String TAG = SslUntrustedCertDialog.class.getSimpleName();
58
59 private X509Certificate mCertificate;
60 private View mView;
61 private SslErrorHandler mHandler;
62
63 private OnSslUntrustedCertListener mListener;
64
65 public SslUntrustedCertDialog() {
66 }
67
68 public SslUntrustedCertDialog(X509Certificate cert, OnSslUntrustedCertListener listener, SslErrorHandler handler) {
69 mCertificate = cert;
70 mListener = listener;
71 mHandler = handler;
72 }
73
74 public static SslUntrustedCertDialog newInstance(Context context, X509Certificate cert, OnSslUntrustedCertListener listener,
75 SslErrorHandler handler) {
76 if (cert != null){
77 SslUntrustedCertDialog dialog = new SslUntrustedCertDialog(cert, listener, handler);
78 return dialog;
79 } else {
80 return null;
81 }
82 }
83
84
85 @Override
86 public void onCreate(Bundle savedInstanceState) {
87 super.onCreate(savedInstanceState);
88 setRetainInstance(true);
89 setCancelable(true);
90 }
91
92 @Override
93 public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
94 // Create a view by inflating desired layout
95 mView = inflater.inflate(R.layout.ssl_untrusted_cert_layout, container, false);
96
97 Button ok = (Button) mView.findViewById(R.id.untrusted_ok);
98 ok.setOnClickListener(new OnClickListener() {
99
100 @Override
101 public void onClick(View v) {
102 try {
103 saveServerCert();
104 dismiss();
105 if (mListener != null) {
106 ((AuthenticatorActivity)getSherlockActivity()).reloadWebView();
107
108 }
109 else
110 Log_OC.d(TAG, "Nobody there to notify the certificate was saved");
111
112 } catch (GeneralSecurityException e) {
113 dismiss();
114 if (mListener != null) {
115 ((AuthenticatorActivity)getSherlockActivity()).cancelWebView();
116 mListener.onFailedSavingCertificate();
117 }
118 Log_OC.e(TAG, "Server certificate could not be saved in the known servers trust store ", e);
119
120 } catch (IOException e) {
121 dismiss();
122 if (mListener != null) {
123 ((AuthenticatorActivity)getSherlockActivity()).cancelWebView();
124 mListener.onFailedSavingCertificate();
125 }
126 Log_OC.e(TAG, "Server certificate could not be saved in the known servers trust store ", e);
127 }
128
129 }
130 });
131
132 Button cancel = (Button) mView.findViewById(R.id.untrusted_cancel);
133 cancel.setOnClickListener(new OnClickListener() {
134
135 @Override
136 public void onClick(View v) {
137 getDialog().cancel();
138 ((AuthenticatorActivity)getSherlockActivity()).cancelWebView();
139 }
140 });
141
142 Button details = (Button) mView.findViewById(R.id.untrusted_details_btn);
143 details.setOnClickListener(new OnClickListener() {
144
145 @Override
146 public void onClick(View v) {
147 View detailsScroll = mView.findViewById(R.id.untrusted_details_scroll);
148 if (detailsScroll.getVisibility() == View.VISIBLE) {
149 detailsScroll.setVisibility(View.GONE);
150 ((Button) v).setText(R.string.ssl_validator_btn_details_see);
151
152 } else {
153 detailsScroll.setVisibility(View.VISIBLE);
154 ((Button) v).setText(R.string.ssl_validator_btn_details_hide);
155
156 showCertificateData(mCertificate);
157 }
158
159 }
160 });
161
162 return mView;
163 }
164
165 @Override
166 public Dialog onCreateDialog(Bundle savedInstanceState) {
167 final Dialog dialog = super.onCreateDialog(savedInstanceState);
168 dialog.requestWindowFeature(Window.FEATURE_NO_TITLE);
169
170 return dialog;
171 }
172
173 @Override
174 public void onDestroyView() {
175 if (getDialog() != null && getRetainInstance())
176 getDialog().setDismissMessage(null);
177 super.onDestroyView();
178 }
179
180 private void showCertificateData(X509Certificate cert) {
181
182 TextView nullCerView = (TextView) mView.findViewById(R.id.untrusted_null_cert);
183
184 if (cert != null) {
185 nullCerView.setVisibility(View.GONE);
186 showSubject(cert.getSubjectX500Principal());
187 showIssuer(cert.getIssuerX500Principal());
188 showValidity(cert.getNotBefore(), cert.getNotAfter());
189 showSignature(cert);
190
191 } else {
192 nullCerView.setVisibility(View.VISIBLE);
193 }
194 }
195
196 private void showSignature(X509Certificate cert) {
197 TextView sigView = ((TextView)mView.findViewById(R.id.untrusted_value_signature));
198 TextView algorithmView = ((TextView)mView.findViewById(R.id.untrusted_value_signature_algorithm));
199 sigView.setText(getHex(cert.getSignature()));
200 algorithmView.setText(cert.getSigAlgName());
201 }
202
203 public String getHex(final byte [] raw) {
204 if (raw == null) {
205 return null;
206 }
207 final StringBuilder hex = new StringBuilder(2 * raw.length);
208 for (final byte b : raw) {
209 final int hiVal = (b & 0xF0) >> 4;
210 final int loVal = b & 0x0F;
211 hex.append((char) ('0' + (hiVal + (hiVal / 10 * 7))));
212 hex.append((char) ('0' + (loVal + (loVal / 10 * 7))));
213 }
214 return hex.toString();
215 }
216
217 @SuppressWarnings("deprecation")
218 private void showValidity(Date notBefore, Date notAfter) {
219 TextView fromView = ((TextView)mView.findViewById(R.id.untrusted_value_validity_from));
220 TextView toView = ((TextView)mView.findViewById(R.id.untrusted_value_validity_to));
221 fromView.setText(notBefore.toLocaleString());
222 toView.setText(notAfter.toLocaleString());
223 }
224
225 private void showSubject(X500Principal subject) {
226 Map<String, String> s = parsePrincipal(subject);
227 TextView cnView = ((TextView)mView.findViewById(R.id.untrusted_value_subject_CN));
228 TextView oView = ((TextView)mView.findViewById(R.id.untrusted_value_subject_O));
229 TextView ouView = ((TextView)mView.findViewById(R.id.untrusted_value_subject_OU));
230 TextView cView = ((TextView)mView.findViewById(R.id.untrusted_value_subject_C));
231 TextView stView = ((TextView)mView.findViewById(R.id.untrusted_value_subject_ST));
232 TextView lView = ((TextView)mView.findViewById(R.id.untrusted_value_subject_L));
233
234 if (s.get("CN") != null) {
235 cnView.setText(s.get("CN"));
236 cnView.setVisibility(View.VISIBLE);
237 } else {
238 cnView.setVisibility(View.GONE);
239 }
240 if (s.get("O") != null) {
241 oView.setText(s.get("O"));
242 oView.setVisibility(View.VISIBLE);
243 } else {
244 oView.setVisibility(View.GONE);
245 }
246 if (s.get("OU") != null) {
247 ouView.setText(s.get("OU"));
248 ouView.setVisibility(View.VISIBLE);
249 } else {
250 ouView.setVisibility(View.GONE);
251 }
252 if (s.get("C") != null) {
253 cView.setText(s.get("C"));
254 cView.setVisibility(View.VISIBLE);
255 } else {
256 cView.setVisibility(View.GONE);
257 }
258 if (s.get("ST") != null) {
259 stView.setText(s.get("ST"));
260 stView.setVisibility(View.VISIBLE);
261 } else {
262 stView.setVisibility(View.GONE);
263 }
264 if (s.get("L") != null) {
265 lView.setText(s.get("L"));
266 lView.setVisibility(View.VISIBLE);
267 } else {
268 lView.setVisibility(View.GONE);
269 }
270 }
271
272 private void showIssuer(X500Principal issuer) {
273 Map<String, String> s = parsePrincipal(issuer);
274 TextView cnView = ((TextView)mView.findViewById(R.id.untrusted_value_issuer_CN));
275 TextView oView = ((TextView)mView.findViewById(R.id.untrusted_value_issuer_O));
276 TextView ouView = ((TextView)mView.findViewById(R.id.untrusted_value_issuer_OU));
277 TextView cView = ((TextView)mView.findViewById(R.id.untrusted_value_issuer_C));
278 TextView stView = ((TextView)mView.findViewById(R.id.untrusted_value_issuer_ST));
279 TextView lView = ((TextView)mView.findViewById(R.id.untrusted_value_issuer_L));
280
281 if (s.get("CN") != null) {
282 cnView.setText(s.get("CN"));
283 cnView.setVisibility(View.VISIBLE);
284 } else {
285 cnView.setVisibility(View.GONE);
286 }
287 if (s.get("O") != null) {
288 oView.setText(s.get("O"));
289 oView.setVisibility(View.VISIBLE);
290 } else {
291 oView.setVisibility(View.GONE);
292 }
293 if (s.get("OU") != null) {
294 ouView.setText(s.get("OU"));
295 ouView.setVisibility(View.VISIBLE);
296 } else {
297 ouView.setVisibility(View.GONE);
298 }
299 if (s.get("C") != null) {
300 cView.setText(s.get("C"));
301 cView.setVisibility(View.VISIBLE);
302 } else {
303 cView.setVisibility(View.GONE);
304 }
305 if (s.get("ST") != null) {
306 stView.setText(s.get("ST"));
307 stView.setVisibility(View.VISIBLE);
308 } else {
309 stView.setVisibility(View.GONE);
310 }
311 if (s.get("L") != null) {
312 lView.setText(s.get("L"));
313 lView.setVisibility(View.VISIBLE);
314 } else {
315 lView.setVisibility(View.GONE);
316 }
317 }
318
319
320 private Map<String, String> parsePrincipal(X500Principal principal) {
321 Map<String, String> result = new HashMap<String, String>();
322 String toParse = principal.getName();
323 String[] pieces = toParse.split(",");
324 String[] tokens = {"CN", "O", "OU", "C", "ST", "L"};
325 for (int i=0; i < pieces.length ; i++) {
326 for (int j=0; j<tokens.length; j++) {
327 if (pieces[i].startsWith(tokens[j] + "=")) {
328 result.put(tokens[j], pieces[i].substring(tokens[j].length()+1));
329 }
330 }
331 }
332 return result;
333 }
334
335 private void saveServerCert() throws KeyStoreException, NoSuchAlgorithmException, CertificateException, IOException {
336 if (mCertificate != null) {
337 // TODO make this asynchronously, it can take some time
338 NetworkUtils.addCertToKnownServersStore(mCertificate, getSherlockActivity());
339 }
340 }
341
342
343 public interface OnSslUntrustedCertListener {
344 public void onFailedSavingCertificate();
345 }
346
347 }