X-Git-Url: http://git.linex4red.de/pub/Android/ownCloud.git/blobdiff_plain/45bc02fbe527ab9b19b806438af7aa828bd54af2..ff82b51e49f40155e7c340090f5ee759af2bf3ad:/src/com/owncloud/android/ui/dialog/SslUntrustedCertDialog.java diff --git a/src/com/owncloud/android/ui/dialog/SslUntrustedCertDialog.java b/src/com/owncloud/android/ui/dialog/SslUntrustedCertDialog.java index 5a67e978..12f595a6 100644 --- a/src/com/owncloud/android/ui/dialog/SslUntrustedCertDialog.java +++ b/src/com/owncloud/android/ui/dialog/SslUntrustedCertDialog.java @@ -1,5 +1,9 @@ -/* ownCloud Android client application - * Copyright (C) 2012-2014 ownCloud Inc. +/** + * ownCloud Android client application + * + * @author masensio + * @author David A. Velasco + * Copyright (C) 2015 ownCloud Inc. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2, @@ -18,176 +22,132 @@ package com.owncloud.android.ui.dialog; import java.io.IOException; import java.security.GeneralSecurityException; -import java.security.KeyStoreException; -import java.security.NoSuchAlgorithmException; -import java.security.cert.CertificateException; import java.security.cert.X509Certificate; -import java.util.Date; -import java.util.HashMap; -import java.util.Map; - -import javax.security.auth.x500.X500Principal; - -import com.actionbarsherlock.app.SherlockActivity; -import com.owncloud.android.R; -import com.owncloud.android.lib.common.network.CertificateCombinedException; -import com.owncloud.android.lib.common.network.NetworkUtils; -import com.owncloud.android.lib.common.operations.RemoteOperationResult; -import com.owncloud.android.utils.Log_OC; import android.app.Activity; import android.app.Dialog; import android.net.http.SslError; import android.os.Bundle; +import android.support.v4.app.DialogFragment; import android.view.LayoutInflater; import android.view.View; -import android.view.View.OnClickListener; import android.view.ViewGroup; import android.view.Window; +import android.view.View.OnClickListener; +import android.webkit.SslErrorHandler; import android.widget.Button; -import android.widget.TextView; + +import com.owncloud.android.R; +import com.owncloud.android.lib.common.network.CertificateCombinedException; +import com.owncloud.android.lib.common.network.NetworkUtils; +import com.owncloud.android.lib.common.utils.Log_OC; +import com.owncloud.android.ui.adapter.CertificateCombinedExceptionViewAdapter; +import com.owncloud.android.ui.adapter.SslCertificateViewAdapter; +import com.owncloud.android.ui.adapter.SslErrorViewAdapter; +import com.owncloud.android.ui.adapter.X509CertificateViewAdapter; /** - * Dialog to show an Untrusted Certificate + * Dialog to show information about an untrusted certificate and allow the user + * to decide trust on it or not. * - * @author masensio - * @author David A. Velasco - * + * Abstract implementation of common functionality for different dialogs that + * get the information about the error and the certificate from different classes. */ -public class SslUntrustedCertDialog extends SslUntrustedCertDialogABSTRACT { +public class SslUntrustedCertDialog extends DialogFragment { private final static String TAG = SslUntrustedCertDialog.class.getSimpleName(); - private X509Certificate mCertificate; - private View mView; - private OnSslUntrustedCertListener mListener; - private SslError mError; - private CertificateCombinedException mException = null; - - public SslUntrustedCertDialog() { - } + protected View mView = null; + protected SslErrorHandler mHandler = null; + protected X509Certificate m509Certificate = null; + + private ErrorViewAdapter mErrorViewAdapter = null; + private CertificateViewAdapter mCertificateViewAdapter = null; - public SslUntrustedCertDialog(X509Certificate cert, SslError error) { - mCertificate = cert; - mError = error; + public static SslUntrustedCertDialog newInstanceForEmptySslError(SslError error, SslErrorHandler handler) { + if (error == null) { + throw new IllegalArgumentException("Trying to create instance with parameter error == null"); + } + if (handler == null) { + throw new IllegalArgumentException("Trying to create instance with parameter handler == null"); + } + SslUntrustedCertDialog dialog = new SslUntrustedCertDialog(); + dialog.mHandler = handler; + dialog.mErrorViewAdapter = new SslErrorViewAdapter(error); + dialog.mCertificateViewAdapter = new SslCertificateViewAdapter(error.getCertificate()); + return dialog; } - /** - * Private constructor. - * - * Instances have to be created through static {@link SslUntrustedCertDialog#newInstance}. - * - * @param context Android context where the dialog will live - * @param e Exception causing the need of prompt the user about the server certificate. - * @param listener Object to notice when the server certificate was added to the local certificates store. - */ - private SslUntrustedCertDialog(RemoteOperationResult result, OnSslUntrustedCertListener listener) { - mListener = listener; - if (result.isSslRecoverableException()) { - mException = (CertificateCombinedException) result.getException(); - mCertificate = mException.getServerCertificate(); + public static SslUntrustedCertDialog newInstanceForFullSslError(CertificateCombinedException sslException) { + if (sslException == null) { + throw new IllegalArgumentException("Trying to create instance with parameter sslException == null"); } + SslUntrustedCertDialog dialog = new SslUntrustedCertDialog(); + dialog.m509Certificate = sslException.getServerCertificate(); + dialog.mErrorViewAdapter = new CertificateCombinedExceptionViewAdapter(sslException); + dialog.mCertificateViewAdapter = new X509CertificateViewAdapter(sslException.getServerCertificate()); + return dialog; } - - public static SslUntrustedCertDialog newInstance(X509Certificate cert, SslError error) { - if (cert != null){ - SslUntrustedCertDialog dialog = new SslUntrustedCertDialog(cert, error); - return dialog; - } else { // TODO Review this case - SslUntrustedCertDialog dialog = new SslUntrustedCertDialog(); - return dialog; + public static SslUntrustedCertDialog newInstanceForFullSslError(X509Certificate cert, SslError error, SslErrorHandler handler) { + if (cert == null) { + throw new IllegalArgumentException("Trying to create instance with parameter cert == null"); + } + if (error == null) { + throw new IllegalArgumentException("Trying to create instance with parameter error == null"); } + if (handler == null) { + throw new IllegalArgumentException("Trying to create instance with parameter handler == null"); + } + SslUntrustedCertDialog dialog = new SslUntrustedCertDialog(); + dialog.m509Certificate = cert; + dialog.mHandler = handler; + dialog.mErrorViewAdapter = new SslErrorViewAdapter(error); + dialog.mCertificateViewAdapter = new X509CertificateViewAdapter(cert); + return dialog; } - - /** - * Creates a new SslUntrustedCertDialog to ask the user if an untrusted certificate from a server should - * be trusted. - * - * @param context Android context where the dialog will live. - * @param result Result of a failed remote operation. - * @param listener Object to notice when the server certificate was added to the local certificates store. - * @return A new SslUntrustedCertDialog instance. NULL if the operation can not be recovered - * by setting the certificate as reliable. - */ - public static SslUntrustedCertDialog newInstance(RemoteOperationResult result, OnSslUntrustedCertListener listener) { - if (result != null && result.isSslRecoverableException()) { - SslUntrustedCertDialog dialog = new SslUntrustedCertDialog(result, listener); - return dialog; - } else { - return null; + @Override + public void onAttach(Activity activity) { + Log_OC.d(TAG, "onAttach"); + super.onAttach(activity); + if (!(activity instanceof OnSslUntrustedCertListener)) { + throw new IllegalArgumentException("The host activity must implement " + OnSslUntrustedCertListener.class.getCanonicalName()); } } + @Override public void onCreate(Bundle savedInstanceState) { + Log_OC.d(TAG, "onCreate, savedInstanceState is " + savedInstanceState); super.onCreate(savedInstanceState); - setRetainInstance(true); - setCancelable(true); - } - - @Override - public void onAttach(Activity activity) { - super.onAttach(activity); - if (activity instanceof SherlockActivity) { - mListener = (OnSslUntrustedCertListener) activity; - } + setRetainInstance(true); // force to keep the state of the fragment on configuration changes (such as device rotations) + setCancelable(false); + mView = null; } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { + Log_OC.d(TAG, "onCreateView, savedInsanceState is " + savedInstanceState); // Create a view by inflating desired layout - mView = inflater.inflate(R.layout.ssl_untrusted_cert_layout, container, false); - - updateMessageException(mException, mError); + if (mView == null) { + mView = inflater.inflate(R.layout.ssl_untrusted_cert_layout, container, false); + mView.findViewById(R.id.details_scroll).setVisibility(View.GONE); + mErrorViewAdapter.updateErrorView(mView); + } else { + ((ViewGroup)mView.getParent()).removeView(mView); + } Button ok = (Button) mView.findViewById(R.id.ok); - ok.setOnClickListener(new OnClickListener() { - - @Override - public void onClick(View v) { - try { - saveServerCert(); - dismiss(); - if (mListener != null) { - mListener.onSavedCertificate(); - } - else - Log_OC.d(TAG, "Nobody there to notify the certificate was saved"); - - } catch (GeneralSecurityException e) { - dismiss(); - if (mListener != null) { - mListener.onFailedSavingCertificate(); - } - Log_OC.e(TAG, "Server certificate could not be saved in the known servers trust store ", e); - - } catch (IOException e) { - dismiss(); - if (mListener != null) { - mListener.onFailedSavingCertificate(); - } - Log_OC.e(TAG, "Server certificate could not be saved in the known servers trust store ", e); - } - - } - }); + ok.setOnClickListener(new OnCertificateTrusted()); Button cancel = (Button) mView.findViewById(R.id.cancel); - cancel.setOnClickListener(new OnClickListener() { - - @Override - public void onClick(View v) { - getDialog().cancel(); - mListener.onCancelCertificate(); - } - }); + cancel.setOnClickListener(new OnCertificateNotTrusted()); Button details = (Button) mView.findViewById(R.id.details_btn); details.setOnClickListener(new OnClickListener() { - + @Override public void onClick(View v) { View detailsScroll = mView.findViewById(R.id.details_scroll); @@ -198,245 +158,85 @@ public class SslUntrustedCertDialog extends SslUntrustedCertDialogABSTRACT { } else { detailsScroll.setVisibility(View.VISIBLE); ((Button) v).setText(R.string.ssl_validator_btn_details_hide); - - showCertificateData(mCertificate); + mCertificateViewAdapter.updateCertificateView(mView); } - } + }); return mView; } + @Override public Dialog onCreateDialog(Bundle savedInstanceState) { + Log_OC.d(TAG, "onCreateDialog, savedInstanceState is " + savedInstanceState); final Dialog dialog = super.onCreateDialog(savedInstanceState); dialog.requestWindowFeature(Window.FEATURE_NO_TITLE); - return dialog; } @Override public void onDestroyView() { + Log_OC.d(TAG, "onDestroyView"); if (getDialog() != null && getRetainInstance()) getDialog().setDismissMessage(null); - super.onDestroyView(); + super.onDestroyView(); } - - private void updateMessageException(CertificateCombinedException exception, SslError error) { - - /// clean - mView.findViewById(R.id.reason_cert_not_trusted).setVisibility(View.GONE); - mView.findViewById(R.id.reason_cert_expired).setVisibility(View.GONE); - mView.findViewById(R.id.reason_cert_not_yet_valid).setVisibility(View.GONE); - mView.findViewById(R.id.reason_hostname_not_verified).setVisibility(View.GONE); - mView.findViewById(R.id.reason_no_info_about_error).setVisibility(View.GONE); - mView.findViewById(R.id.details_scroll).setVisibility(View.GONE); + private class OnCertificateNotTrusted implements OnClickListener { - - if (exception != null) { - - /// refresh - if (exception.getCertPathValidatorException() != null) { - ((TextView)mView.findViewById(R.id.reason_cert_not_trusted)).setVisibility(View.VISIBLE); - } - - if (exception.getCertificateExpiredException() != null) { - ((TextView)mView.findViewById(R.id.reason_cert_expired)).setVisibility(View.VISIBLE); - } - - if (exception.getCertificateNotYetValidException() != null) { - ((TextView)mView.findViewById(R.id.reason_cert_not_yet_valid)).setVisibility(View.VISIBLE); - } - - if (exception.getSslPeerUnverifiedException() != null) { - ((TextView)mView.findViewById(R.id.reason_hostname_not_verified)).setVisibility(View.VISIBLE); - } - - } else if ( error != null) { - /// refresh - if (error.getPrimaryError() == SslError.SSL_UNTRUSTED) { - ((TextView)mView.findViewById(R.id.reason_cert_not_trusted)).setVisibility(View.VISIBLE); - - } else if (error.getPrimaryError() == SslError.SSL_EXPIRED) { - ((TextView)mView.findViewById(R.id.reason_cert_expired)).setVisibility(View.VISIBLE); - - } else if (error.getPrimaryError() == SslError.SSL_NOTYETVALID) { - ((TextView)mView.findViewById(R.id.reason_cert_not_yet_valid)).setVisibility(View.VISIBLE); - - } else if (error.getPrimaryError() == SslError.SSL_IDMISMATCH) { - ((TextView)mView.findViewById(R.id.reason_hostname_not_verified)).setVisibility(View.VISIBLE); + @Override + public void onClick(View v) { + getDialog().cancel(); + if (mHandler != null) { + mHandler.cancel(); } + ((OnSslUntrustedCertListener)getActivity()).onCancelCertificate(); } - } - private void showCertificateData(X509Certificate cert) { - - TextView nullCerView = (TextView) mView.findViewById(R.id.null_cert); - - if (cert != null) { - nullCerView.setVisibility(View.GONE); - showSubject(cert.getSubjectX500Principal()); - showIssuer(cert.getIssuerX500Principal()); - showValidity(cert.getNotBefore(), cert.getNotAfter()); - showSignature(cert); - - } else { - nullCerView.setVisibility(View.VISIBLE); - } - } - - private void showSignature(X509Certificate cert) { - TextView sigView = ((TextView)mView.findViewById(R.id.value_signature)); - TextView algorithmView = ((TextView)mView.findViewById(R.id.value_signature_algorithm)); - sigView.setText(getHex(cert.getSignature())); - algorithmView.setText(cert.getSigAlgName()); - } - public String getHex(final byte [] raw) { - if (raw == null) { - return null; - } - final StringBuilder hex = new StringBuilder(2 * raw.length); - for (final byte b : raw) { - final int hiVal = (b & 0xF0) >> 4; - final int loVal = b & 0x0F; - hex.append((char) ('0' + (hiVal + (hiVal / 10 * 7)))); - hex.append((char) ('0' + (loVal + (loVal / 10 * 7)))); - } - return hex.toString(); - } + private class OnCertificateTrusted implements OnClickListener { - @SuppressWarnings("deprecation") - private void showValidity(Date notBefore, Date notAfter) { - TextView fromView = ((TextView)mView.findViewById(R.id.value_validity_from)); - TextView toView = ((TextView)mView.findViewById(R.id.value_validity_to)); - fromView.setText(notBefore.toLocaleString()); - toView.setText(notAfter.toLocaleString()); - } - - private void showSubject(X500Principal subject) { - Map s = parsePrincipal(subject); - TextView cnView = ((TextView)mView.findViewById(R.id.value_subject_CN)); - TextView oView = ((TextView)mView.findViewById(R.id.value_subject_O)); - TextView ouView = ((TextView)mView.findViewById(R.id.value_subject_OU)); - TextView cView = ((TextView)mView.findViewById(R.id.value_subject_C)); - TextView stView = ((TextView)mView.findViewById(R.id.value_subject_ST)); - TextView lView = ((TextView)mView.findViewById(R.id.value_subject_L)); - - if (s.get("CN") != null) { - cnView.setText(s.get("CN")); - cnView.setVisibility(View.VISIBLE); - } else { - cnView.setVisibility(View.GONE); - } - if (s.get("O") != null) { - oView.setText(s.get("O")); - oView.setVisibility(View.VISIBLE); - } else { - oView.setVisibility(View.GONE); - } - if (s.get("OU") != null) { - ouView.setText(s.get("OU")); - ouView.setVisibility(View.VISIBLE); - } else { - ouView.setVisibility(View.GONE); - } - if (s.get("C") != null) { - cView.setText(s.get("C")); - cView.setVisibility(View.VISIBLE); - } else { - cView.setVisibility(View.GONE); - } - if (s.get("ST") != null) { - stView.setText(s.get("ST")); - stView.setVisibility(View.VISIBLE); - } else { - stView.setVisibility(View.GONE); - } - if (s.get("L") != null) { - lView.setText(s.get("L")); - lView.setVisibility(View.VISIBLE); - } else { - lView.setVisibility(View.GONE); - } - } - - private void showIssuer(X500Principal issuer) { - Map s = parsePrincipal(issuer); - TextView cnView = ((TextView)mView.findViewById(R.id.value_issuer_CN)); - TextView oView = ((TextView)mView.findViewById(R.id.value_issuer_O)); - TextView ouView = ((TextView)mView.findViewById(R.id.value_issuer_OU)); - TextView cView = ((TextView)mView.findViewById(R.id.value_issuer_C)); - TextView stView = ((TextView)mView.findViewById(R.id.value_issuer_ST)); - TextView lView = ((TextView)mView.findViewById(R.id.value_issuer_L)); - - if (s.get("CN") != null) { - cnView.setText(s.get("CN")); - cnView.setVisibility(View.VISIBLE); - } else { - cnView.setVisibility(View.GONE); - } - if (s.get("O") != null) { - oView.setText(s.get("O")); - oView.setVisibility(View.VISIBLE); - } else { - oView.setVisibility(View.GONE); - } - if (s.get("OU") != null) { - ouView.setText(s.get("OU")); - ouView.setVisibility(View.VISIBLE); - } else { - ouView.setVisibility(View.GONE); - } - if (s.get("C") != null) { - cView.setText(s.get("C")); - cView.setVisibility(View.VISIBLE); - } else { - cView.setVisibility(View.GONE); - } - if (s.get("ST") != null) { - stView.setText(s.get("ST")); - stView.setVisibility(View.VISIBLE); - } else { - stView.setVisibility(View.GONE); - } - if (s.get("L") != null) { - lView.setText(s.get("L")); - lView.setVisibility(View.VISIBLE); - } else { - lView.setVisibility(View.GONE); - } - } + @Override + public void onClick(View v) { + dismiss(); + if (mHandler != null) { + mHandler.proceed(); + } + if (m509Certificate != null) { + Activity activity = getActivity(); + try { + NetworkUtils.addCertToKnownServersStore(m509Certificate, activity); // TODO make this asynchronously, it can take some time + ((OnSslUntrustedCertListener)activity).onSavedCertificate(); - - private Map parsePrincipal(X500Principal principal) { - Map result = new HashMap(); - String toParse = principal.getName(); - String[] pieces = toParse.split(","); - String[] tokens = {"CN", "O", "OU", "C", "ST", "L"}; - for (int i=0; i < pieces.length ; i++) { - for (int j=0; j