Explorar el Código

Merge pull request #437 from owncloud/check_server_certificates_in_SSO_webview

Check server certificates in SAML SSO webview and allow the user trust or not in case of problems
masensio hace 11 años
padre
commit
68271bbf82

+ 1 - 1
owncloud-android-library

@@ -1 +1 @@
-Subproject commit 1dbc9a121e8818d0202d3aaec31bce1335ee428b
+Subproject commit 268681dbffbd15b820fd0a29211c62c88135203d

+ 460 - 0
res/layout/ssl_untrusted_cert_layout.xml

@@ -0,0 +1,460 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 
+    ownCloud Android client application
+
+    Copyright (C) 2012-2013 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,
+    as published by the Free Software Foundation.
+  
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+-->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/root"
+    android:layout_width="wrap_content"
+    android:layout_height="wrap_content"
+    android:gravity="center"
+    android:orientation="vertical" >
+
+	<TextView
+		android:id="@+id/header"
+		android:layout_width="wrap_content"
+		android:layout_height="wrap_content"
+		android:layout_weight="0"
+		android:text="@string/ssl_validator_header"
+		android:padding="5dp"
+		android:textAppearance="?android:attr/textAppearanceMedium"
+		 />
+    
+	<TextView
+		android:id="@+id/reason_cert_not_trusted"
+		android:layout_width="wrap_content"
+		android:layout_height="wrap_content"
+		android:layout_weight="0"
+		android:layout_gravity="left"
+		android:paddingLeft="20dp"
+		android:text="@string/ssl_validator_reason_cert_not_trusted"
+		android:textAppearance="?android:attr/textAppearanceSmall"
+		 />
+		
+	
+	<TextView
+		android:id="@+id/reason_cert_expired"
+		android:layout_width="wrap_content"
+		android:layout_height="wrap_content"
+		android:layout_gravity="left"
+		android:paddingLeft="20dp"
+		android:text="@string/ssl_validator_reason_cert_expired"
+		android:textAppearance="?android:attr/textAppearanceSmall"
+		 />
+	
+	<TextView
+		android:id="@+id/reason_cert_not_yet_valid"
+		android:layout_width="wrap_content"
+		android:layout_height="wrap_content"
+		android:layout_gravity="left"
+		android:paddingLeft="20dp"
+		android:text="@string/ssl_validator_reason_cert_not_yet_valid"
+		android:textAppearance="?android:attr/textAppearanceSmall"
+		 />
+		
+	<TextView
+		android:id="@+id/reason_hostname_not_verified"
+		android:layout_width="wrap_content"
+		android:layout_height="wrap_content"
+		android:layout_gravity="left"
+		android:paddingLeft="20dp"
+		android:text="@string/ssl_validator_reason_hostname_not_verified"
+		android:textAppearance="?android:attr/textAppearanceSmall"
+		 />
+	
+	<TextView
+		android:id="@+id/reason_no_info_about_error"
+		android:layout_width="wrap_content"
+		android:layout_height="wrap_content"
+		android:layout_gravity="left"
+		android:paddingLeft="20dp"
+		android:text="@string/ssl_validator_no_info_about_error"
+		android:textAppearance="?android:attr/textAppearanceSmall"
+		 />
+	
+    <ScrollView 
+        android:id="@+id/details_scroll"
+        android:visibility="gone" 
+    	android:padding="20dp"
+        android:layout_width="match_parent"
+        android:layout_height="0dp"
+        android:layout_weight="1"
+        >
+        
+		<LinearLayout 
+    		android:id="@+id/details_view"
+    		android:layout_width="wrap_content"
+    		android:layout_height="wrap_content"
+    		android:gravity="left"
+    		android:orientation="vertical" >
+    			
+		    <TextView
+		        android:id="@+id/null_cert"
+		        android:layout_width="wrap_content"
+		        android:layout_height="wrap_content"
+		        android:layout_gravity="left"
+		        android:paddingLeft="20dp"
+		        android:text="@string/ssl_validator_null_cert"
+		        android:textAppearance="?android:attr/textAppearanceSmall" />
+
+				<TextView
+        			android:id="@+id/label_subject"
+        			android:layout_width="wrap_content"
+        			android:layout_height="wrap_content"
+					android:paddingBottom="5dp"
+        			android:text="@string/ssl_validator_label_subject"
+        			android:textAppearance="?android:attr/textAppearanceMedium"
+        		/>
+				
+				<TextView
+				    android:id="@+id/label_subject_CN"
+				    android:layout_width="wrap_content"
+				    android:layout_height="wrap_content"
+				    android:text="@string/ssl_validator_label_CN"
+				    android:textAppearance="?android:attr/textAppearanceSmall"
+				/>
+			    
+				<TextView
+				    android:id="@+id/value_subject_CN"
+				    android:layout_width="wrap_content"
+				    android:layout_height="wrap_content"
+				    android:paddingBottom="5dp"
+				    android:text=""
+				    android:textAppearance="?android:attr/textAppearanceSmall"
+				/>
+				
+				<TextView
+				    android:id="@+id/label_subject_O"
+				    android:layout_width="wrap_content"
+				    android:layout_height="wrap_content"
+				    android:text="@string/ssl_validator_label_O"
+				    android:textAppearance="?android:attr/textAppearanceSmall"
+				/>
+			    
+				<TextView
+				    android:id="@+id/value_subject_O"
+				    android:layout_width="wrap_content"
+				    android:layout_height="wrap_content"
+				    android:paddingBottom="5dp"
+				    android:text=""
+				    android:textAppearance="?android:attr/textAppearanceSmall"
+				/>
+				
+				<TextView
+				    android:id="@+id/label_subject_OU"
+				    android:layout_width="wrap_content"
+				    android:layout_height="wrap_content"
+				    android:text="@string/ssl_validator_label_OU"
+				    android:textAppearance="?android:attr/textAppearanceSmall"
+				/>
+			    
+				<TextView
+				    android:id="@+id/value_subject_OU"
+				    android:layout_width="wrap_content"
+				    android:layout_height="wrap_content"
+				    android:paddingBottom="5dp"
+				    android:text=""
+				    android:textAppearance="?android:attr/textAppearanceSmall"
+				/>
+				
+				<TextView
+				    android:id="@+id/label_subject_ST"
+				    android:layout_width="wrap_content"
+				    android:layout_height="wrap_content"
+				    android:text="@string/ssl_validator_label_ST"
+				    android:textAppearance="?android:attr/textAppearanceSmall"
+				/>
+			    
+				<TextView
+				    android:id="@+id/value_subject_ST"
+				    android:layout_width="wrap_content"
+				    android:layout_height="wrap_content"
+				    android:paddingBottom="5dp"
+				    android:text=""
+				    android:textAppearance="?android:attr/textAppearanceSmall"
+				/>
+
+				<TextView
+				    android:id="@+id/label_subject_C"
+				    android:layout_width="wrap_content"
+				    android:layout_height="wrap_content"
+				    android:text="@string/ssl_validator_label_C"
+				    android:textAppearance="?android:attr/textAppearanceSmall"
+				/>
+				
+				<TextView
+				    android:id="@+id/value_subject_C"
+				    android:layout_width="wrap_content"
+				    android:layout_height="wrap_content"
+				    android:paddingBottom="5dp"
+				    android:text=""
+				    android:textAppearance="?android:attr/textAppearanceSmall"
+				/>
+				
+				<TextView
+				    android:id="@+id/label_subject_L"
+				    android:layout_width="wrap_content"
+				    android:layout_height="wrap_content"
+				    android:text="@string/ssl_validator_label_L"
+				    android:textAppearance="?android:attr/textAppearanceSmall"
+				/>
+			    
+				<TextView
+				    android:id="@+id/value_subject_L"
+				    android:layout_width="wrap_content"
+				    android:layout_height="wrap_content"
+				    android:paddingBottom="5dp"
+				    android:text=""
+				    android:textAppearance="?android:attr/textAppearanceSmall"
+				/>
+			    
+
+				<TextView
+        			android:id="@+id/label_issuer"
+        			android:layout_width="wrap_content"
+        			android:layout_height="wrap_content"
+					android:paddingBottom="5dp"
+        			android:text="@string/ssl_validator_label_issuer"
+        			android:textAppearance="?android:attr/textAppearanceMedium"
+        		/>
+				
+				<TextView
+				    android:id="@+id/label_issuer_CN"
+				    android:layout_width="wrap_content"
+				    android:layout_height="wrap_content"
+				    android:text="@string/ssl_validator_label_CN"
+				    android:textAppearance="?android:attr/textAppearanceSmall"
+				/>
+			    
+				<TextView
+				    android:id="@+id/value_issuer_CN"
+				    android:layout_width="wrap_content"
+				    android:layout_height="wrap_content"
+				    android:paddingBottom="5dp"
+				    android:text=""
+				    android:textAppearance="?android:attr/textAppearanceSmall"
+				/>
+				
+				<TextView
+				    android:id="@+id/label_issuer_O"
+				    android:layout_width="wrap_content"
+				    android:layout_height="wrap_content"
+				    android:text="@string/ssl_validator_label_O"
+				    android:textAppearance="?android:attr/textAppearanceSmall"
+				/>
+			    
+				<TextView
+				    android:id="@+id/value_issuer_O"
+				    android:layout_width="wrap_content"
+				    android:layout_height="wrap_content"
+				    android:paddingBottom="5dp"
+				    android:text=""
+				    android:textAppearance="?android:attr/textAppearanceSmall"
+				/>
+				
+				<TextView
+				    android:id="@+id/label_issuer_OU"
+				    android:layout_width="wrap_content"
+				    android:layout_height="wrap_content"
+				    android:text="@string/ssl_validator_label_OU"
+				    android:textAppearance="?android:attr/textAppearanceSmall"
+				/>
+			    
+				<TextView
+				    android:id="@+id/value_issuer_OU"
+				    android:layout_width="wrap_content"
+				    android:layout_height="wrap_content"
+				    android:paddingBottom="5dp"
+				    android:text=""
+				    android:textAppearance="?android:attr/textAppearanceSmall"
+				/>
+				
+				<TextView
+				    android:id="@+id/label_issuer_ST"
+				    android:layout_width="wrap_content"
+				    android:layout_height="wrap_content"
+				    android:text="@string/ssl_validator_label_ST"
+				    android:textAppearance="?android:attr/textAppearanceSmall"
+				/>
+			    
+				<TextView
+				    android:id="@+id/value_issuer_ST"
+				    android:layout_width="wrap_content"
+				    android:layout_height="wrap_content"
+				    android:paddingBottom="5dp"
+				    android:text=""
+				    android:textAppearance="?android:attr/textAppearanceSmall"
+				/>
+
+				<TextView
+				    android:id="@+id/label_issuer_C"
+				    android:layout_width="wrap_content"
+				    android:layout_height="wrap_content"
+				    android:text="@string/ssl_validator_label_C"
+				    android:textAppearance="?android:attr/textAppearanceSmall"
+				/>
+				
+				<TextView
+				    android:id="@+id/value_issuer_C"
+				    android:layout_width="wrap_content"
+				    android:layout_height="wrap_content"
+				    android:paddingBottom="5dp"
+				    android:text=""
+				    android:textAppearance="?android:attr/textAppearanceSmall"
+				/>
+				
+				<TextView
+				    android:id="@+id/label_issuer_L"
+				    android:layout_width="wrap_content"
+				    android:layout_height="wrap_content"
+				    android:text="@string/ssl_validator_label_L"
+				    android:textAppearance="?android:attr/textAppearanceSmall"
+				/>
+			    
+				<TextView
+				    android:id="@+id/value_issuer_L"
+				    android:layout_width="wrap_content"
+				    android:layout_height="wrap_content"
+				    android:paddingBottom="5dp"
+				    android:text=""
+				    android:textAppearance="?android:attr/textAppearanceSmall"
+				/>
+			    
+				<TextView
+        			android:id="@+id/label_validity"
+        			android:layout_width="wrap_content"
+        			android:layout_height="wrap_content"
+					android:paddingBottom="5dp"
+        			android:text="@string/ssl_validator_label_validity"
+        			android:textAppearance="?android:attr/textAppearanceMedium"
+        		/>
+				
+				<TextView
+				    android:id="@+id/label_validity_from"
+				    android:layout_width="wrap_content"
+				    android:layout_height="wrap_content"
+				    android:text="@string/ssl_validator_label_validity_from"
+				    android:textAppearance="?android:attr/textAppearanceSmall"
+				/>
+			    
+				<TextView
+				    android:id="@+id/value_validity_from"
+				    android:layout_width="wrap_content"
+				    android:layout_height="wrap_content"
+				    android:paddingBottom="5dp"
+				    android:text=""
+				    android:textAppearance="?android:attr/textAppearanceSmall"
+				/>
+				
+				<TextView
+				    android:id="@+id/label_validity_to"
+				    android:layout_width="wrap_content"
+				    android:layout_height="wrap_content"
+				    android:text="@string/ssl_validator_label_validity_to"
+				    android:textAppearance="?android:attr/textAppearanceSmall"
+				/>
+			    
+				<TextView
+				    android:id="@+id/value_validity_to"
+				    android:layout_width="wrap_content"
+				    android:layout_height="wrap_content"
+				    android:paddingBottom="5dp"
+				    android:text=""
+				    android:textAppearance="?android:attr/textAppearanceSmall"
+				/>
+				
+
+				<TextView
+        			android:id="@+id/label_signature"
+        			android:layout_width="wrap_content"
+        			android:layout_height="wrap_content"
+					android:paddingBottom="5dp"
+        			android:text="@string/ssl_validator_label_signature"
+        			android:textAppearance="?android:attr/textAppearanceMedium"
+        		/>
+				
+				<TextView
+        			android:id="@+id/label_signature_algorithm"
+        			android:layout_width="wrap_content"
+        			android:layout_height="wrap_content"
+        			android:text="@string/ssl_validator_label_signature_algorithm"
+        			android:textAppearance="?android:attr/textAppearanceSmall"
+        		/>
+				
+				<TextView
+        			android:id="@+id/value_signature_algorithm"
+        			android:layout_width="wrap_content"
+        			android:layout_height="wrap_content"
+					android:paddingBottom="5dp"
+        			android:text=""
+        			android:textAppearance="?android:attr/textAppearanceSmall"
+        		/>
+																								
+								
+				<TextView
+        			android:id="@+id/value_signature"
+        			android:layout_width="wrap_content"
+        			android:layout_height="wrap_content"
+					android:paddingBottom="5dp"
+        			android:text=""
+        			android:textAppearance="?android:attr/textAppearanceSmall"
+        		/>
+				
+		</LinearLayout>
+		
+    </ScrollView>
+	
+	<TextView
+        android:id="@+id/question"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+		android:layout_weight="0"
+		android:padding="5dp"
+        android:text="@string/ssl_validator_question"
+        android:textAppearance="?android:attr/textAppearanceMedium"
+        >
+    </TextView>
+
+	<LinearLayout
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+		android:layout_weight="0"
+        android:gravity="center" >
+
+        <Button
+            android:id="@+id/cancel"
+            android:layout_width="0dp"
+            android:layout_height="wrap_content"
+            android:layout_weight="1"
+            android:text="@string/common_cancel" />
+
+        <Button
+            android:id="@+id/details_btn"
+            android:layout_width="0dp"
+            android:layout_height="wrap_content"
+            android:layout_weight="1"
+            android:text="@string/ssl_validator_btn_details_see" />
+
+        <Button
+            android:id="@+id/ok"
+            android:layout_width="0dp"
+            android:layout_height="wrap_content"
+            android:layout_weight="1"
+            android:text="@string/common_ok" />
+
+    </LinearLayout>
+
+</LinearLayout>

+ 1 - 1
res/layout/ssl_validator_layout.xml

@@ -79,7 +79,7 @@
         android:layout_width="wrap_content"
         android:layout_height="180dp">
         
-		<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+		<LinearLayout
     		android:id="@+id/details_view"
     		android:layout_width="wrap_content"
     		android:layout_height="wrap_content"

+ 2 - 2
res/layout/sso_dialog.xml

@@ -21,13 +21,13 @@
     android:layout_height="wrap_content"
     >
     
-    <com.owncloud.android.ui.dialog.SsoWebView
+    <!--  com.owncloud.android.ui.dialog.SsoWebView
     	android:layout_width="wrap_content"
     	android:layout_height="wrap_content"
         android:id="@+id/sso_webview"
         android:focusable="true"
         android:focusableInTouchMode="true"
         android:clickable="true"
-        />
+        /-->
 
 </RelativeLayout>

+ 2 - 0
res/values/strings.xml

@@ -216,6 +216,8 @@
 	<string name="ssl_validator_label_validity_to">To:</string>
 	<string name="ssl_validator_label_signature">Signature:</string>
 	<string name="ssl_validator_label_signature_algorithm">Algorithm:</string>
+	<string name="ssl_validator_null_cert">The certificate could not be shown.</string>
+	<string name="ssl_validator_no_info_about_error">- No information about the error</string>
 			
     <string name="placeholder_sentence">This is a placeholder</string>
     <string name="placeholder_filename">placeholder.txt</string>

+ 98 - 37
src/com/owncloud/android/authentication/AuthenticatorActivity.java

@@ -18,6 +18,8 @@
 
 package com.owncloud.android.authentication;
 
+import java.security.cert.X509Certificate;
+
 import android.accounts.Account;
 import android.accounts.AccountManager;
 import android.app.AlertDialog;
@@ -29,10 +31,13 @@ import android.content.SharedPreferences;
 import android.graphics.Rect;
 import android.graphics.drawable.Drawable;
 import android.net.Uri;
+import android.net.http.SslError;
 import android.os.Bundle;
 import android.os.Handler;
 import android.preference.PreferenceManager;
 import android.support.v4.app.Fragment;
+import android.support.v4.app.FragmentManager;
+import android.support.v4.app.FragmentTransaction;
 import android.text.Editable;
 import android.text.InputType;
 import android.text.TextWatcher;
@@ -43,6 +48,7 @@ import android.view.View.OnFocusChangeListener;
 import android.view.View.OnTouchListener;
 import android.view.Window;
 import android.view.inputmethod.EditorInfo;
+import android.webkit.SslErrorHandler;
 import android.widget.Button;
 import android.widget.CheckBox;
 import android.widget.EditText;
@@ -59,6 +65,7 @@ import com.owncloud.android.lib.common.OwnCloudClientFactory;
 import com.owncloud.android.lib.common.OwnCloudClient;
 import com.owncloud.android.operations.OAuth2GetAccessToken;
 
+import com.owncloud.android.lib.common.network.CertificateCombinedException;
 import com.owncloud.android.lib.common.operations.OnRemoteOperationListener;
 import com.owncloud.android.lib.resources.status.GetRemoteStatusOperation;
 import com.owncloud.android.lib.common.operations.RemoteOperation;
@@ -68,8 +75,8 @@ import com.owncloud.android.lib.resources.files.ExistenceCheckRemoteOperation;
 import com.owncloud.android.lib.resources.users.GetRemoteUserNameOperation;
 
 import com.owncloud.android.ui.dialog.SamlWebViewDialog;
-import com.owncloud.android.ui.dialog.SslValidatorDialog;
-import com.owncloud.android.ui.dialog.SslValidatorDialog.OnSslValidatorListener;
+import com.owncloud.android.ui.dialog.SslUntrustedCertDialog;
+import com.owncloud.android.ui.dialog.SslUntrustedCertDialog.OnSslUntrustedCertListener;
 import com.owncloud.android.utils.Log_OC;
 import com.owncloud.android.lib.resources.status.OwnCloudVersion;
 
@@ -80,7 +87,8 @@ import com.owncloud.android.lib.resources.status.OwnCloudVersion;
  * @author David A. Velasco
  */
 public class AuthenticatorActivity extends AccountAuthenticatorActivity
-implements  OnRemoteOperationListener, OnSslValidatorListener, OnFocusChangeListener, OnEditorActionListener, SsoWebViewClientListener{
+    implements  OnRemoteOperationListener, OnFocusChangeListener, OnEditorActionListener, 
+    SsoWebViewClientListener, OnSslUntrustedCertListener {
 
     private static final String TAG = AuthenticatorActivity.class.getSimpleName();
 
@@ -113,9 +121,8 @@ implements  OnRemoteOperationListener, OnSslValidatorListener, OnFocusChangeList
     private static final String AUTH_OPTIONAL = "optional";
     
     private static final int DIALOG_LOGIN_PROGRESS = 0;
-    private static final int DIALOG_SSL_VALIDATOR = 1;
-    private static final int DIALOG_CERT_NOT_SAVED = 2;
-    private static final int DIALOG_OAUTH2_LOGIN_PROGRESS = 3;
+    private static final int DIALOG_CERT_NOT_SAVED = 1;
+    private static final int DIALOG_OAUTH2_LOGIN_PROGRESS = 2;
 
     public static final byte ACTION_CREATE = 0;
     public static final byte ACTION_UPDATE_TOKEN = 1;
@@ -135,7 +142,6 @@ implements  OnRemoteOperationListener, OnSslValidatorListener, OnFocusChangeList
     private Thread mOperationThread;
     private GetRemoteStatusOperation mOcServerChkOperation;
     private ExistenceCheckRemoteOperation mAuthCheckOperation;
-    private RemoteOperationResult mLastSslUntrustedServerResult;
 
     private Uri mNewCapturedUriFromOAuth2Redirection;
 
@@ -168,6 +174,8 @@ implements  OnRemoteOperationListener, OnSslValidatorListener, OnFocusChangeList
     
     private boolean mResumed; // Control if activity is resumed
 
+    public static String DIALOG_UNTRUSTED_CERT = "DIALOG_UNTRUSTED_CERT";
+
 
     /**
      * {@inheritDoc}
@@ -893,8 +901,7 @@ implements  OnRemoteOperationListener, OnSslValidatorListener, OnFocusChangeList
 
             /// very special case (TODO: move to a common place for all the remote operations)
             if (result.getCode() == ResultCode.SSL_RECOVERABLE_PEER_UNVERIFIED) {
-                mLastSslUntrustedServerResult = result;
-                showDialog(DIALOG_SSL_VALIDATOR); 
+                showUntrustedCertDialog(result);
             }
 
             /// retrieve discovered version and normalize server URL
@@ -1198,8 +1205,7 @@ implements  OnRemoteOperationListener, OnSslValidatorListener, OnFocusChangeList
 
             // very special case (TODO: move to a common place for all the remote operations) (dangerous here?)
             if (result.getCode() == ResultCode.SSL_RECOVERABLE_PEER_UNVERIFIED) {
-                mLastSslUntrustedServerResult = result;
-                showDialog(DIALOG_SSL_VALIDATOR); 
+                showUntrustedCertDialog(result);
             }
 
         } else {    // authorization fail due to client side - probably wrong credentials
@@ -1331,10 +1337,6 @@ implements  OnRemoteOperationListener, OnSslValidatorListener, OnFocusChangeList
         case DIALOG_CERT_NOT_SAVED:
         case DIALOG_OAUTH2_LOGIN_PROGRESS:
             break;
-        case DIALOG_SSL_VALIDATOR: {
-            ((SslValidatorDialog)dialog).updateResult(mLastSslUntrustedServerResult);
-            break;
-        }
         default:
             Log_OC.e(TAG, "Incorrect dialog called with id = " + id);
         }
@@ -1385,11 +1387,6 @@ implements  OnRemoteOperationListener, OnSslValidatorListener, OnFocusChangeList
             dialog = working_dialog;
             break;
         }
-        case DIALOG_SSL_VALIDATOR: {
-            /// TODO start to use new dialog interface, at least for this (it is a FragmentDialog already)
-            dialog = SslValidatorDialog.newInstance(this, mLastSslUntrustedServerResult, this);
-            break;
-        }
         case DIALOG_CERT_NOT_SAVED: {
             AlertDialog.Builder builder = new AlertDialog.Builder(this);
             builder.setMessage(getResources().getString(R.string.ssl_validator_not_saved));
@@ -1539,23 +1536,6 @@ implements  OnRemoteOperationListener, OnSslValidatorListener, OnFocusChangeList
         }
     }
     
-    /**
-     * Called from SslValidatorDialog when a new server certificate was correctly saved.
-     */
-    public void onSavedCertificate() {
-        checkOcServer();
-    }
-
-    /**
-     * Called from SslValidatorDialog when a new server certificate could not be saved 
-     * when the user requested it.
-     */
-    @Override
-    public void onFailedSavingCertificate() {
-        showDialog(DIALOG_CERT_NOT_SAVED);
-    }
-
-
     /**
      *  Called when the 'action' button in an IME is pressed ('enter' in software keyboard).
      * 
@@ -1670,5 +1650,86 @@ implements  OnRemoteOperationListener, OnSslValidatorListener, OnFocusChangeList
         }
         return super.onTouchEvent(event);
     }
+
+
+    /**
+     * Show untrusted cert dialog 
+     */
+    public void showUntrustedCertDialog(X509Certificate x509Certificate, SslError error, SslErrorHandler handler) {
+        // Show a dialog with the certificate info
+        SslUntrustedCertDialog dialog = null;
+        if (x509Certificate == null) {
+            dialog = SslUntrustedCertDialog.newInstanceForEmptySslError(error, handler);
+        } else {
+            dialog = SslUntrustedCertDialog.newInstanceForFullSslError(x509Certificate, error, handler);
+        }
+        FragmentManager fm = getSupportFragmentManager();
+        FragmentTransaction ft = fm.beginTransaction();
+        ft.addToBackStack(null);
+        dialog.show(ft, DIALOG_UNTRUSTED_CERT);
+    }
+    
+    /**
+     * Show untrusted cert dialog 
+     */
+    public void showUntrustedCertDialog(RemoteOperationResult result) {
+        // Show a dialog with the certificate info
+        SslUntrustedCertDialog dialog = SslUntrustedCertDialog.newInstanceForFullSslError((CertificateCombinedException)result.getException());
+        FragmentManager fm = getSupportFragmentManager();
+        FragmentTransaction ft = fm.beginTransaction();
+        ft.addToBackStack(null);
+        dialog.show(ft, DIALOG_UNTRUSTED_CERT);
+        
+    }
     
+    /**
+     * Dismiss untrusted cert dialog
+     */
+    public void dismissUntrustedCertDialog(){
+        /*Fragment frag = getSupportFragmentManager().findFragmentByTag(DIALOG_UNTRUSTED_CERT);
+        if (frag != null) {
+            SslErrorViewAdapter dialog = (SslErrorViewAdapter) frag;
+            dialog.dismiss();
+        }
+        */
+    }
+    
+    /**
+     * Called from SslValidatorDialog when a new server certificate was correctly saved.
+     */
+    public void onSavedCertificate() {
+        Fragment fd = getSupportFragmentManager().findFragmentByTag(TAG_SAML_DIALOG);
+        if (fd == null) {
+            // if SAML dialog is not shown, the SslDialog was shown due to an SSL error in the server check
+            checkOcServer();
+        }
+    }
+
+    /**
+     * Called from SslValidatorDialog when a new server certificate could not be saved 
+     * when the user requested it.
+     */
+    @Override
+    public void onFailedSavingCertificate() {
+        showDialog(DIALOG_CERT_NOT_SAVED);
+        cancelWebView();
+    }
+
+    @Override
+    public void onCancelCertificate() {
+        cancelWebView();
+    }
+    
+
+    public void cancelWebView() {
+        Fragment fd = getSupportFragmentManager().findFragmentByTag(TAG_SAML_DIALOG);
+        if (fd != null && fd instanceof SherlockDialogFragment) {
+            Dialog d = ((SherlockDialogFragment)fd).getDialog();
+            if (d != null && d.isShowing()) {
+                d.dismiss();
+            }
+        }
+        
+    }
+
 }

+ 55 - 3
src/com/owncloud/android/authentication/SsoWebViewClient.java

@@ -17,12 +17,21 @@
 
 package com.owncloud.android.authentication;
 
+import java.io.ByteArrayInputStream;
 import java.lang.ref.WeakReference;
+import java.security.cert.Certificate;
+import java.security.cert.CertificateException;
+import java.security.cert.CertificateFactory;
+import java.security.cert.X509Certificate;
 
+import com.owncloud.android.lib.common.network.NetworkUtils;
 import com.owncloud.android.utils.Log_OC;
 
+import android.content.Context;
 import android.graphics.Bitmap;
+import android.net.http.SslCertificate;
 import android.net.http.SslError;
+import android.os.Bundle;
 import android.os.Handler;
 import android.os.Message;
 import android.view.KeyEvent;
@@ -52,12 +61,14 @@ public class SsoWebViewClient extends WebViewClient {
         public void onSsoFinished(String sessionCookie);
     }
     
+    private Context mContext;
     private Handler mListenerHandler;
     private WeakReference<SsoWebViewClientListener> mListenerRef;
     private String mTargetUrl;
     private String mLastReloadedUrlAtError;
     
-    public SsoWebViewClient (Handler listenerHandler, SsoWebViewClientListener listener) {
+    public SsoWebViewClient (Context context, Handler listenerHandler, SsoWebViewClientListener listener) {
+        mContext = context;
         mListenerHandler = listenerHandler;
         mListenerRef = new WeakReference<SsoWebViewClient.SsoWebViewClientListener>(listener);
         mTargetUrl = "fake://url.to.be.set";
@@ -135,9 +146,50 @@ public class SsoWebViewClient extends WebViewClient {
     }
     
     @Override
-    public void onReceivedSslError (WebView view, SslErrorHandler handler, SslError error) {
+    public void onReceivedSslError (final WebView view, final SslErrorHandler handler, SslError error) {
         Log_OC.d(TAG, "onReceivedSslError : " + error);
-        handler.proceed();
+        // Test 1
+        X509Certificate x509Certificate = getX509CertificateFromError(error);
+        boolean isKnownServer = false;
+        
+        if (x509Certificate != null) {
+            Log_OC.d(TAG, "------>>>>> x509Certificate " + x509Certificate.toString());
+            
+            try {
+                isKnownServer = NetworkUtils.isCertInKnownServersStore((Certificate) x509Certificate, mContext);
+            } catch (Exception e) {
+                Log_OC.e(TAG, "Exception: " + e.getMessage());
+            }
+        }
+        
+         if (isKnownServer) {
+             handler.proceed();
+         } else {
+             ((AuthenticatorActivity)mContext).showUntrustedCertDialog(x509Certificate, error, handler);
+         }
+    }
+    
+    /**
+     * Obtain the X509Certificate from SslError
+     * @param   error     SslError
+     * @return  X509Certificate from error
+     */
+    public X509Certificate getX509CertificateFromError (SslError error) {
+        Bundle bundle = SslCertificate.saveState(error.getCertificate());
+        X509Certificate x509Certificate;
+        byte[] bytes = bundle.getByteArray("x509-certificate");
+        if (bytes == null) {
+            x509Certificate = null;
+        } else {
+            try {
+                CertificateFactory certFactory = CertificateFactory.getInstance("X.509");
+                Certificate cert = certFactory.generateCertificate(new ByteArrayInputStream(bytes));
+                x509Certificate = (X509Certificate) cert;
+            } catch (CertificateException e) {
+                x509Certificate = null;
+            }
+        }        
+        return x509Certificate;
     }
     
     @Override

+ 0 - 2
src/com/owncloud/android/syncadapter/FileSyncAdapter.java

@@ -30,7 +30,6 @@ import com.owncloud.android.R;
 import com.owncloud.android.authentication.AuthenticatorActivity;
 import com.owncloud.android.datamodel.FileDataStorageManager;
 import com.owncloud.android.datamodel.OCFile;
-import com.owncloud.android.lib.common.accounts.AccountUtils.Constants;
 import com.owncloud.android.lib.common.operations.RemoteOperationResult;
 import com.owncloud.android.operations.SynchronizeFolderOperation;
 import com.owncloud.android.operations.UpdateOCVersionOperation;
@@ -41,7 +40,6 @@ import com.owncloud.android.utils.Log_OC;
 
 
 import android.accounts.Account;
-import android.accounts.AccountManager;
 import android.accounts.AccountsException;
 import android.app.Notification;
 import android.app.NotificationManager;

+ 0 - 1
src/com/owncloud/android/ui/activity/CopyToClipboardActivity.java

@@ -22,7 +22,6 @@ import com.owncloud.android.R;
 import android.app.Activity;
 import android.content.ClipData;
 import android.content.Intent;
-import android.os.Build;
 import android.os.Bundle;
 import android.text.ClipboardManager;
 import android.widget.Toast;

+ 29 - 24
src/com/owncloud/android/ui/activity/FileDisplayActivity.java

@@ -19,7 +19,6 @@
 package com.owncloud.android.ui.activity;
 
 import java.io.File;
-
 import android.accounts.Account;
 import android.app.AlertDialog;
 import android.app.Dialog;
@@ -34,7 +33,6 @@ import android.content.IntentFilter;
 import android.content.ServiceConnection;
 import android.content.SharedPreferences;
 import android.content.SyncRequest;
-import android.content.res.Configuration;
 import android.content.res.Resources.NotFoundException;
 import android.database.Cursor;
 import android.net.Uri;
@@ -43,6 +41,7 @@ import android.os.IBinder;
 import android.preference.PreferenceManager;
 import android.provider.MediaStore;
 import android.support.v4.app.Fragment;
+import android.support.v4.app.FragmentManager;
 import android.support.v4.app.FragmentTransaction;
 //import android.support.v4.content.LocalBroadcastManager;
 import android.util.Log;
@@ -68,6 +67,7 @@ import com.owncloud.android.files.services.FileDownloader.FileDownloaderBinder;
 import com.owncloud.android.files.services.FileUploader.FileUploaderBinder;
 import com.owncloud.android.operations.CreateFolderOperation;
 
+import com.owncloud.android.lib.common.network.CertificateCombinedException;
 import com.owncloud.android.lib.common.operations.RemoteOperation;
 import com.owncloud.android.lib.common.operations.RemoteOperationResult;
 import com.owncloud.android.lib.common.operations.RemoteOperationResult.ResultCode;
@@ -79,10 +79,11 @@ import com.owncloud.android.operations.SynchronizeFolderOperation;
 import com.owncloud.android.operations.UnshareLinkOperation;
 import com.owncloud.android.services.OperationsService;
 import com.owncloud.android.syncadapter.FileSyncAdapter;
+import com.owncloud.android.ui.adapter.SslErrorViewAdapter;
 import com.owncloud.android.ui.dialog.EditNameDialog;
+import com.owncloud.android.ui.dialog.SslUntrustedCertDialog;
 import com.owncloud.android.ui.dialog.EditNameDialog.EditNameDialogListener;
-import com.owncloud.android.ui.dialog.SslValidatorDialog;
-import com.owncloud.android.ui.dialog.SslValidatorDialog.OnSslValidatorListener;
+import com.owncloud.android.ui.dialog.SslUntrustedCertDialog.OnSslUntrustedCertListener;
 import com.owncloud.android.ui.fragment.FileDetailFragment;
 import com.owncloud.android.ui.fragment.FileFragment;
 import com.owncloud.android.ui.fragment.OCFileListFragment;
@@ -101,7 +102,7 @@ import com.owncloud.android.utils.Log_OC;
  */
 
 public class FileDisplayActivity extends HookActivity implements
-OCFileListFragment.ContainerActivity, FileDetailFragment.ContainerActivity, OnNavigationListener, OnSslValidatorListener, EditNameDialogListener {
+OCFileListFragment.ContainerActivity, FileDetailFragment.ContainerActivity, OnNavigationListener, OnSslUntrustedCertListener, EditNameDialogListener {
 
     private ArrayAdapter<String> mDirectories;
 
@@ -125,8 +126,8 @@ OCFileListFragment.ContainerActivity, FileDetailFragment.ContainerActivity, OnNa
 
     public static final int DIALOG_SHORT_WAIT = 0;
     private static final int DIALOG_CHOOSE_UPLOAD_SOURCE = 1;
-    private static final int DIALOG_SSL_VALIDATOR = 2;
-    private static final int DIALOG_CERT_NOT_SAVED = 3;
+    //private static final int DIALOG_SSL_VALIDATOR = 2;
+    private static final int DIALOG_CERT_NOT_SAVED = 2;
     
     public static final String ACTION_DETAILS = "com.owncloud.android.ui.activity.action.DETAILS";
 
@@ -143,6 +144,8 @@ OCFileListFragment.ContainerActivity, FileDetailFragment.ContainerActivity, OnNa
     private boolean mSyncInProgress = false;
     //private boolean mRefreshSharesInProgress = false;
 
+    private String DIALOG_UNTRUSTED_CERT;
+    
     private OCFile mWaitingToSend;
 
     @Override
@@ -744,14 +747,6 @@ OCFileListFragment.ContainerActivity, FileDetailFragment.ContainerActivity, OnNa
     }
 
 
-    @Override
-    protected void onPrepareDialog(int id, Dialog dialog, Bundle args) {
-        if (id == DIALOG_SSL_VALIDATOR && mLastSslUntrustedServerResult != null) {
-            ((SslValidatorDialog)dialog).updateResult(mLastSslUntrustedServerResult);
-        }
-    }
-
-
     @Override
     protected Dialog onCreateDialog(int id) {
         Dialog dialog = null;
@@ -810,10 +805,6 @@ OCFileListFragment.ContainerActivity, FileDetailFragment.ContainerActivity, OnNa
             dialog = builder.create();
             break;
         }
-        case DIALOG_SSL_VALIDATOR: {
-            dialog = SslValidatorDialog.newInstance(this, mLastSslUntrustedServerResult, this);
-            break;
-        }
         case DIALOG_CERT_NOT_SAVED: {
             builder = new AlertDialog.Builder(this);
             builder.setMessage(getResources().getString(R.string.ssl_validator_not_saved));
@@ -982,7 +973,6 @@ OCFileListFragment.ContainerActivity, FileDetailFragment.ContainerActivity, OnNa
             if (synchResult != null) {
                 if (synchResult.getCode().equals(RemoteOperationResult.ResultCode.SSL_RECOVERABLE_PEER_UNVERIFIED)) {
                     mLastSslUntrustedServerResult = synchResult;
-                    showDialog(DIALOG_SSL_VALIDATOR); 
                 }
             }
         }
@@ -1078,7 +1068,7 @@ OCFileListFragment.ContainerActivity, FileDetailFragment.ContainerActivity, OnNa
                 if ((getSharesResult != null) &&
                         RemoteOperationResult.ResultCode.SSL_RECOVERABLE_PEER_UNVERIFIED.equals(getSharesResult.getCode())) {
                     mLastSslUntrustedServerResult = getSharesResult;
-                    showDialog(DIALOG_SSL_VALIDATOR); 
+                    showUntrustedCertDialog(mLastSslUntrustedServerResult);
                 }
 
                 //setSupportProgressBarIndeterminateVisibility(mRefreshSharesInProgress || mSyncInProgress);
@@ -1324,6 +1314,10 @@ OCFileListFragment.ContainerActivity, FileDetailFragment.ContainerActivity, OnNa
         showDialog(DIALOG_CERT_NOT_SAVED);
     }
 
+    @Override
+    public void onCancelCertificate() {
+        // nothing to do
+    }
 
     /**
      * Updates the view associated to the activity after the finish of some operation over files
@@ -1421,7 +1415,7 @@ OCFileListFragment.ContainerActivity, FileDetailFragment.ContainerActivity, OnNa
             msg.show();
             if (result.isSslRecoverableException()) {
                 mLastSslUntrustedServerResult = result;
-                showDialog(DIALOG_SSL_VALIDATOR); 
+                showUntrustedCertDialog(mLastSslUntrustedServerResult);
             }
         }
     }
@@ -1488,7 +1482,7 @@ OCFileListFragment.ContainerActivity, FileDetailFragment.ContainerActivity, OnNa
                 msg.show();
                 if (result.isSslRecoverableException()) {
                     mLastSslUntrustedServerResult = result;
-                    showDialog(DIALOG_SSL_VALIDATOR); 
+                    showUntrustedCertDialog(mLastSslUntrustedServerResult);
                 }
             }
         }
@@ -1613,7 +1607,18 @@ OCFileListFragment.ContainerActivity, FileDetailFragment.ContainerActivity, OnNa
         mRefreshSharesInProgress = true;
     }
     */
-
+    
+    /**
+     * Show untrusted cert dialog 
+     */
+    public void showUntrustedCertDialog(RemoteOperationResult result) {
+        // Show a dialog with the certificate info
+        SslUntrustedCertDialog dialog = SslUntrustedCertDialog.newInstanceForFullSslError((CertificateCombinedException)result.getException());
+        FragmentManager fm = getSupportFragmentManager();
+        FragmentTransaction ft = fm.beginTransaction();
+        dialog.show(ft, DIALOG_UNTRUSTED_CERT);
+    }
+    
     /**
      * Requests the download of the received {@link OCFile} , updates the UI
      * to monitor the download progress and prepares the activity to send the file

+ 74 - 0
src/com/owncloud/android/ui/adapter/CertificateCombinedExceptionViewAdapter.java

@@ -0,0 +1,74 @@
+/* ownCloud Android client application
+ *   Copyright (C) 2012-2014 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,
+ *   as published by the Free Software Foundation.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+package com.owncloud.android.ui.adapter;
+
+import com.owncloud.android.R;
+import com.owncloud.android.lib.common.network.CertificateCombinedException;
+import com.owncloud.android.ui.dialog.SslUntrustedCertDialog;
+
+import android.view.View;
+import android.widget.TextView;
+
+/**
+ * TODO
+ * 
+ * @author masensio
+ * @author David A. Velasco
+ *
+ */
+public class CertificateCombinedExceptionViewAdapter implements SslUntrustedCertDialog.ErrorViewAdapter {
+    
+    //private final static String TAG = CertificateCombinedExceptionViewAdapter.class.getSimpleName();
+    
+    private CertificateCombinedException mSslException = null;
+    
+    public CertificateCombinedExceptionViewAdapter(CertificateCombinedException sslException) {
+        mSslException = sslException;
+    }
+    
+    @Override
+    public void updateErrorView(View dialogView) {
+        /// clean
+        dialogView.findViewById(R.id.reason_no_info_about_error).setVisibility(View.GONE);
+       
+        /// refresh
+        if (mSslException.getCertPathValidatorException() != null) {
+            ((TextView)dialogView.findViewById(R.id.reason_cert_not_trusted)).setVisibility(View.VISIBLE);
+        } else {
+            dialogView.findViewById(R.id.reason_cert_not_trusted).setVisibility(View.GONE);
+        }
+        
+        if (mSslException.getCertificateExpiredException() != null) {
+            ((TextView)dialogView.findViewById(R.id.reason_cert_expired)).setVisibility(View.VISIBLE);
+        } else {
+            dialogView.findViewById(R.id.reason_cert_expired).setVisibility(View.GONE);
+        }
+        
+        if (mSslException.getCertificateNotYetValidException() != null) {
+            ((TextView)dialogView.findViewById(R.id.reason_cert_not_yet_valid)).setVisibility(View.VISIBLE);
+        } else {
+            dialogView.findViewById(R.id.reason_cert_not_yet_valid).setVisibility(View.GONE);
+        }
+
+        if (mSslException.getSslPeerUnverifiedException() != null) {
+            ((TextView)dialogView.findViewById(R.id.reason_hostname_not_verified)).setVisibility(View.VISIBLE);
+        } else {
+            dialogView.findViewById(R.id.reason_hostname_not_verified).setVisibility(View.GONE);
+        }
+        
+    }
+}

+ 126 - 0
src/com/owncloud/android/ui/adapter/SslCertificateViewAdapter.java

@@ -0,0 +1,126 @@
+/* ownCloud Android client application
+ *   Copyright (C) 2012-2014 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,
+ *   as published by the Free Software Foundation.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+package com.owncloud.android.ui.adapter;
+
+import java.text.DateFormat;
+import java.util.Date;
+
+import com.owncloud.android.R;
+import com.owncloud.android.ui.dialog.SslUntrustedCertDialog;
+import android.net.http.SslCertificate;
+import android.view.View;
+import android.widget.TextView;
+
+/**
+ * TODO
+ * 
+ * @author masensio
+ * @author David A. Velasco
+ */
+public class SslCertificateViewAdapter implements SslUntrustedCertDialog.CertificateViewAdapter {
+    
+    //private final static String TAG = SslCertificateViewAdapter.class.getSimpleName();
+    
+    private SslCertificate mCertificate;
+
+    
+    /**
+     * Constructor
+     * 
+     * @param 
+     */
+    public SslCertificateViewAdapter(SslCertificate certificate) {
+        mCertificate = certificate;
+    }
+
+    @Override
+    public void updateCertificateView(View dialogView) {
+        TextView nullCerView = (TextView) dialogView.findViewById(R.id.null_cert);
+        if (mCertificate != null) {
+            nullCerView.setVisibility(View.GONE);
+            showSubject(mCertificate.getIssuedTo(), dialogView);
+            showIssuer(mCertificate.getIssuedBy(), dialogView);
+            showValidity(mCertificate.getValidNotBeforeDate(), mCertificate.getValidNotAfterDate(), dialogView);
+            hideSignature(dialogView);
+            
+        } else {
+            nullCerView.setVisibility(View.VISIBLE);
+        }
+    }
+    
+    private void showValidity(Date notBefore, Date notAfter, View dialogView) {
+        TextView fromView = ((TextView)dialogView.findViewById(R.id.value_validity_from));
+        TextView toView = ((TextView)dialogView.findViewById(R.id.value_validity_to));
+        DateFormat dateFormat = DateFormat.getDateInstance();
+        fromView.setText(dateFormat.format(notBefore));
+        toView.setText(dateFormat.format(notAfter));
+    }
+
+    
+    private void showSubject(SslCertificate.DName subject, View dialogView) {
+        TextView cnView = ((TextView)dialogView.findViewById(R.id.value_subject_CN));
+        cnView.setText(subject.getCName());
+        cnView.setVisibility(View.VISIBLE);
+        
+        TextView oView = ((TextView)dialogView.findViewById(R.id.value_subject_O));
+        oView.setText(subject.getOName());
+        oView.setVisibility(View.VISIBLE);
+        
+        TextView ouView = ((TextView)dialogView.findViewById(R.id.value_subject_OU));
+        ouView.setText(subject.getUName());
+        ouView.setVisibility(View.VISIBLE);
+
+        // SslCertificates don't offer this information
+        ((TextView)dialogView.findViewById(R.id.value_subject_C)).setVisibility(View.GONE);
+        ((TextView)dialogView.findViewById(R.id.value_subject_ST)).setVisibility(View.GONE);
+        ((TextView)dialogView.findViewById(R.id.value_subject_L)).setVisibility(View.GONE);
+        ((TextView)dialogView.findViewById(R.id.label_subject_C)).setVisibility(View.GONE);
+        ((TextView)dialogView.findViewById(R.id.label_subject_ST)).setVisibility(View.GONE);
+        ((TextView)dialogView.findViewById(R.id.label_subject_L)).setVisibility(View.GONE);
+    }
+    
+    
+    private void showIssuer(SslCertificate.DName issuer, View dialogView) {
+        TextView cnView = ((TextView)dialogView.findViewById(R.id.value_issuer_CN));
+        cnView.setText(issuer.getCName());
+        cnView.setVisibility(View.VISIBLE);
+        
+        TextView oView = ((TextView)dialogView.findViewById(R.id.value_issuer_O));
+        oView.setText(issuer.getOName());
+        oView.setVisibility(View.VISIBLE);
+
+        TextView ouView = ((TextView)dialogView.findViewById(R.id.value_issuer_OU));
+        ouView.setText(issuer.getUName());
+        ouView.setVisibility(View.VISIBLE);
+        
+        // SslCertificates don't offer this information
+        ((TextView)dialogView.findViewById(R.id.value_issuer_C)).setVisibility(View.GONE);
+        ((TextView)dialogView.findViewById(R.id.value_issuer_ST)).setVisibility(View.GONE);
+        ((TextView)dialogView.findViewById(R.id.value_issuer_L)).setVisibility(View.GONE);
+        ((TextView)dialogView.findViewById(R.id.label_issuer_C)).setVisibility(View.GONE);
+        ((TextView)dialogView.findViewById(R.id.label_issuer_ST)).setVisibility(View.GONE);
+        ((TextView)dialogView.findViewById(R.id.label_issuer_L)).setVisibility(View.GONE);
+    }
+    
+    private void hideSignature(View dialogView) {
+        ((TextView)dialogView.findViewById(R.id.label_signature)).setVisibility(View.GONE);
+        ((TextView)dialogView.findViewById(R.id.label_signature_algorithm)).setVisibility(View.GONE);
+        ((TextView)dialogView.findViewById(R.id.value_signature_algorithm)).setVisibility(View.GONE);
+        ((TextView)dialogView.findViewById(R.id.value_signature)).setVisibility(View.GONE);
+    }
+
+}

+ 73 - 0
src/com/owncloud/android/ui/adapter/SslErrorViewAdapter.java

@@ -0,0 +1,73 @@
+/* ownCloud Android client application
+ *   Copyright (C) 2012-2014 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,
+ *   as published by the Free Software Foundation.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+package com.owncloud.android.ui.adapter;
+
+import com.owncloud.android.R;
+import com.owncloud.android.ui.dialog.SslUntrustedCertDialog;
+import android.net.http.SslError;
+import android.view.View;
+import android.widget.TextView;
+
+/**
+ * Dialog to show an Untrusted Certificate
+ * 
+ * @author masensio
+ * @author David A. Velasco
+ *
+ */
+public class SslErrorViewAdapter implements SslUntrustedCertDialog.ErrorViewAdapter {
+    
+    //private final static String TAG = SslErrorViewAdapter.class.getSimpleName();
+    
+    private SslError mSslError;
+    
+    public SslErrorViewAdapter(SslError sslError) {
+        mSslError = sslError;
+    }
+    
+    @Override
+    public void updateErrorView(View dialogView) {
+        /// clean
+        dialogView.findViewById(R.id.reason_no_info_about_error).setVisibility(View.GONE);
+        
+        /// refresh
+        if (mSslError.hasError(SslError.SSL_UNTRUSTED)) {
+            ((TextView)dialogView.findViewById(R.id.reason_cert_not_trusted)).setVisibility(View.VISIBLE);
+        } else {
+            dialogView.findViewById(R.id.reason_cert_not_trusted).setVisibility(View.GONE);
+        }
+        
+        if (mSslError.hasError(SslError.SSL_EXPIRED)) {
+            ((TextView)dialogView.findViewById(R.id.reason_cert_expired)).setVisibility(View.VISIBLE);
+        } else {
+            dialogView.findViewById(R.id.reason_cert_expired).setVisibility(View.GONE);
+        }
+        
+        if (mSslError.getPrimaryError() == SslError.SSL_NOTYETVALID) {
+            ((TextView)dialogView.findViewById(R.id.reason_cert_not_yet_valid)).setVisibility(View.VISIBLE);
+        } else {
+            dialogView.findViewById(R.id.reason_cert_not_yet_valid).setVisibility(View.GONE);
+        }
+        
+        if (mSslError.getPrimaryError() == SslError.SSL_IDMISMATCH) {
+            ((TextView)dialogView.findViewById(R.id.reason_hostname_not_verified)).setVisibility(View.VISIBLE);
+        } else {
+            dialogView.findViewById(R.id.reason_hostname_not_verified).setVisibility(View.GONE);
+        }
+    }
+
+}

+ 204 - 0
src/com/owncloud/android/ui/adapter/X509CertificateViewAdapter.java

@@ -0,0 +1,204 @@
+/* ownCloud Android client application
+ *   Copyright (C) 2012-2014 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,
+ *   as published by the Free Software Foundation.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+package com.owncloud.android.ui.adapter;
+
+import java.security.cert.X509Certificate;
+import java.text.DateFormat;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.security.auth.x500.X500Principal;
+
+import com.owncloud.android.R;
+import com.owncloud.android.ui.dialog.SslUntrustedCertDialog;
+
+import android.view.View;
+import android.widget.TextView;
+
+/**
+ * 
+ * @author masensio
+ * @author David A. Velasco
+ *
+ */
+public class X509CertificateViewAdapter implements SslUntrustedCertDialog.CertificateViewAdapter {
+    
+    //private final static String TAG = X509CertificateViewAdapter.class.getSimpleName();
+    
+    private X509Certificate mCertificate = null;
+    
+    public X509CertificateViewAdapter(X509Certificate certificate) {
+        mCertificate = certificate;
+    }
+    
+    @Override
+    public void updateCertificateView(View dialogView) {
+        TextView nullCerView = (TextView) dialogView.findViewById(R.id.null_cert);
+        
+        if (mCertificate != null) {
+            nullCerView.setVisibility(View.GONE);
+            showSubject(mCertificate.getSubjectX500Principal(), dialogView);
+            showIssuer(mCertificate.getIssuerX500Principal(), dialogView);
+            showValidity(mCertificate.getNotBefore(), mCertificate.getNotAfter(), dialogView);
+            showSignature(dialogView);
+            
+        } else {
+            nullCerView.setVisibility(View.VISIBLE);
+        }
+    }
+
+    private void showSignature(View dialogView) {
+        TextView sigView = ((TextView)dialogView.findViewById(R.id.value_signature));
+        TextView algorithmView = ((TextView)dialogView.findViewById(R.id.value_signature_algorithm));
+        sigView.setText(getHex(mCertificate.getSignature()));
+        algorithmView.setText(mCertificate.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 void showValidity(Date notBefore, Date notAfter, View dialogView) {
+        TextView fromView = ((TextView)dialogView.findViewById(R.id.value_validity_from));
+        TextView toView = ((TextView)dialogView.findViewById(R.id.value_validity_to));
+        DateFormat dateFormat = DateFormat.getDateInstance();
+        fromView.setText(dateFormat.format(notBefore));
+        toView.setText(dateFormat.format(notAfter));
+    }
+
+    private void showSubject(X500Principal subject, View dialogView) {
+        Map<String, String> s = parsePrincipal(subject);
+        TextView cnView = ((TextView)dialogView.findViewById(R.id.value_subject_CN));
+        TextView oView = ((TextView)dialogView.findViewById(R.id.value_subject_O));
+        TextView ouView = ((TextView)dialogView.findViewById(R.id.value_subject_OU));
+        TextView cView = ((TextView)dialogView.findViewById(R.id.value_subject_C));
+        TextView stView = ((TextView)dialogView.findViewById(R.id.value_subject_ST));
+        TextView lView = ((TextView)dialogView.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, View dialogView) {
+        Map<String, String> s = parsePrincipal(issuer);
+        TextView cnView = ((TextView)dialogView.findViewById(R.id.value_issuer_CN));
+        TextView oView = ((TextView)dialogView.findViewById(R.id.value_issuer_O));
+        TextView ouView = ((TextView)dialogView.findViewById(R.id.value_issuer_OU));
+        TextView cView = ((TextView)dialogView.findViewById(R.id.value_issuer_C));
+        TextView stView = ((TextView)dialogView.findViewById(R.id.value_issuer_ST));
+        TextView lView = ((TextView)dialogView.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);
+        }
+    }
+    
+
+    private Map<String, String> parsePrincipal(X500Principal principal) {
+        Map<String, String> result = new HashMap<String, String>();
+        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<tokens.length; j++) {
+                if (pieces[i].startsWith(tokens[j] + "=")) {
+                    result.put(tokens[j], pieces[i].substring(tokens[j].length()+1));
+                }
+            }
+        }
+        return result;
+    }
+
+}

+ 16 - 0
src/com/owncloud/android/ui/dialog/LoadingDialog.java

@@ -1,3 +1,19 @@
+/* ownCloud Android client application
+ *   Copyright (C) 2012-2014 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,
+ *   as published by the Free Software Foundation.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
 package com.owncloud.android.ui.dialog;
 
 import com.owncloud.android.R;

+ 53 - 67
src/com/owncloud/android/ui/dialog/SamlWebViewDialog.java

@@ -1,5 +1,5 @@
 /* ownCloud Android client application
- *   Copyright (C) 2012-2013 ownCloud Inc.
+ *   Copyright (C) 2012-2014 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,
@@ -30,9 +30,9 @@ import android.view.View;
 import android.view.ViewGroup;
 import android.webkit.CookieManager;
 import android.webkit.CookieSyncManager;
-import android.webkit.WebBackForwardList;
 import android.webkit.WebSettings;
 import android.webkit.WebView;
+import android.widget.RelativeLayout;
 
 import com.actionbarsherlock.app.SherlockDialogFragment;
 import com.owncloud.android.R;
@@ -56,7 +56,6 @@ public class SamlWebViewDialog extends SherlockDialogFragment {
 
     private static final String ARG_INITIAL_URL = "INITIAL_URL";
     private static final String ARG_TARGET_URL = "TARGET_URL";
-    private static final String KEY_WEBVIEW_STATE = "WEBVIEW_STATE";
     
     private WebView mSsoWebView;
     private SsoWebViewClient mWebViewClient;
@@ -68,9 +67,6 @@ public class SamlWebViewDialog extends SherlockDialogFragment {
 
     private SsoWebViewClientListener mSsoWebViewClientListener;
 
-    //private View mSsoRootView;
-
-
     /**
      * Public factory method to get dialog instances.
      * 
@@ -103,7 +99,7 @@ public class SamlWebViewDialog extends SherlockDialogFragment {
         try {
             mSsoWebViewClientListener = (SsoWebViewClientListener) activity;
             mHandler = new Handler();
-            mWebViewClient = new SsoWebViewClient(mHandler, mSsoWebViewClientListener);
+            mWebViewClient = new SsoWebViewClient(activity, mHandler, mSsoWebViewClientListener);
             
        } catch (ClassCastException e) {
             throw new ClassCastException(activity.toString() + " must implement " + SsoWebViewClientListener.class.getSimpleName());
@@ -114,10 +110,12 @@ public class SamlWebViewDialog extends SherlockDialogFragment {
     @SuppressLint("SetJavaScriptEnabled")
     @Override
     public void onCreate(Bundle savedInstanceState) {
-        Log_OC.d(TAG, "onCreate");
+        Log_OC.d(TAG, "onCreate, savedInstanceState is " + savedInstanceState);
         super.onCreate(savedInstanceState);
         
-        CookieSyncManager.createInstance(getActivity());
+        setRetainInstance(true);
+        
+        CookieSyncManager.createInstance(getSherlockActivity().getApplicationContext());
 
         if (savedInstanceState == null) {
             mInitialUrl = getArguments().getString(ARG_INITIAL_URL);
@@ -130,82 +128,68 @@ public class SamlWebViewDialog extends SherlockDialogFragment {
         setStyle(SherlockDialogFragment.STYLE_NO_TITLE, R.style.Theme_ownCloud_Dialog);
     }
     
-    @Override
-    public Dialog onCreateDialog(Bundle savedInstanceState) {
-        Log_OC.d(TAG, "onCreateDialog");
-
-        /*
-        // build the dialog
-        AlertDialog.Builder builder = new AlertDialog.Builder(getSherlockActivity());
-        if (mSsoRootView.getParent() != null) {
-            ((ViewGroup)(mSsoRootView.getParent())).removeView(mSsoRootView);
-        }
-        builder.setView(mSsoRootView);
-        //builder.setView(mSsoWebView);
-        Dialog dialog = builder.create();
-        */
-        
-        return super.onCreateDialog(savedInstanceState);
-    }
-
+    @SuppressWarnings("deprecation")
     @SuppressLint("SetJavaScriptEnabled")
     @Override
     public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
-        Log_OC.d(TAG, "onCreateView");
+        Log_OC.d(TAG, "onCreateView, savedInsanceState is " + savedInstanceState);
         
         // Inflate layout of the dialog  
-        View rootView = inflater.inflate(R.layout.sso_dialog, container, false);  // null parent view because it will go in the dialog layout
-        mSsoWebView  = (WebView) rootView.findViewById(R.id.sso_webview);
-            
-        mWebViewClient.setTargetUrl(mTargetUrl);
-        mSsoWebView.setWebViewClient(mWebViewClient);
+        RelativeLayout ssoRootView = (RelativeLayout) inflater.inflate(R.layout.sso_dialog, container, false);  // null parent view because it will go in the dialog layout
         
-        if (savedInstanceState == null) {
-            Log_OC.d(TAG,  "   initWebView start");
+        if (mSsoWebView == null) {
+            // initialize the WebView
+            mSsoWebView = new SsoWebView(getSherlockActivity().getApplicationContext());
+            mSsoWebView.setFocusable(true);
+            mSsoWebView.setFocusableInTouchMode(true);
+            mSsoWebView.setClickable(true);
+            
             CookieManager cookieManager = CookieManager.getInstance();
             cookieManager.setAcceptCookie(true);
             cookieManager.removeAllCookie();
             mSsoWebView.loadUrl(mInitialUrl);
-            
-        } else {
-            Log_OC.d(TAG, "   restoreWebView start");
-            WebBackForwardList history = mSsoWebView.restoreState(savedInstanceState.getBundle(KEY_WEBVIEW_STATE));
-            if (history == null) {
-                Log_OC.e(TAG, "Error restoring WebView state ; back to starting URL");
-                mSsoWebView.loadUrl(mInitialUrl);
-            }
+          
+            WebSettings webSettings = mSsoWebView.getSettings();
+            webSettings.setJavaScriptEnabled(true);
+            webSettings.setBuiltInZoomControls(false);
+            webSettings.setLoadWithOverviewMode(false);
+            webSettings.setSavePassword(false);
+            webSettings.setUserAgentString(OwnCloudClient.USER_AGENT);
+            webSettings.setSaveFormData(false);
         }
-
-        WebSettings webSettings = mSsoWebView.getSettings();
-        webSettings.setJavaScriptEnabled(true);
-        webSettings.setBuiltInZoomControls(true);
-        webSettings.setLoadWithOverviewMode(false);
-        webSettings.setSavePassword(false);
-        webSettings.setUserAgentString(OwnCloudClient.USER_AGENT);
-        webSettings.setSaveFormData(false);
         
-        return rootView;
+        mWebViewClient.setTargetUrl(mTargetUrl);
+        mSsoWebView.setWebViewClient(mWebViewClient);
+        
+        // add the webview into the layout
+        RelativeLayout.LayoutParams layoutParams = new RelativeLayout.LayoutParams(
+                RelativeLayout.LayoutParams.WRAP_CONTENT, 
+                RelativeLayout.LayoutParams.WRAP_CONTENT
+                );
+        ssoRootView.addView(mSsoWebView, layoutParams);
+        ssoRootView.requestLayout();
+        
+        return ssoRootView;
     }
 
     @Override
     public void onSaveInstanceState(Bundle outState) {
-        Log_OC.d(SAML_DIALOG_TAG, "onSaveInstanceState being CALLED");
+        Log_OC.d(TAG, "onSaveInstanceState being CALLED");
         super.onSaveInstanceState(outState);
         
         // save URLs
         outState.putString(ARG_INITIAL_URL, mInitialUrl);
         outState.putString(ARG_TARGET_URL, mTargetUrl);
-        
-        // Save the state of the WebView
-        Bundle webviewState = new Bundle();
-        mSsoWebView.saveState(webviewState);
-        outState.putBundle(KEY_WEBVIEW_STATE, webviewState);
     }
 
     @Override
     public void onDestroyView() {
         Log_OC.d(TAG, "onDestroyView");
         
+        if ((ViewGroup)mSsoWebView.getParent() != null) {
+            ((ViewGroup)mSsoWebView.getParent()).removeView(mSsoWebView);
+        }
+        
         mSsoWebView.setWebViewClient(null);
         
         // Work around bug: http://code.google.com/p/android/issues/detail?id=17423
@@ -235,50 +219,52 @@ public class SamlWebViewDialog extends SherlockDialogFragment {
     
     @Override
     public void onCancel (DialogInterface dialog) {
-        Log_OC.d(SAML_DIALOG_TAG, "onCancel");
+        Log_OC.d(TAG, "onCancel");
         super.onCancel(dialog);
     }
     
     @Override
     public void onDismiss (DialogInterface dialog) {
-        Log_OC.d(SAML_DIALOG_TAG, "onDismiss");
+        Log_OC.d(TAG, "onDismiss");
         super.onDismiss(dialog);
     }
     
     @Override
     public void onStart() {
-        Log_OC.d(SAML_DIALOG_TAG, "onStart");
+        Log_OC.d(TAG, "onStart");
         super.onStart();
     }
 
     @Override
     public void onStop() {
-        Log_OC.d(SAML_DIALOG_TAG, "onStop");
+        Log_OC.d(TAG, "onStop");
         super.onStop();
     }
 
     @Override
     public void onResume() {
-        Log_OC.d(SAML_DIALOG_TAG, "onResume");
+        Log_OC.d(TAG, "onResume");
         super.onResume();
+        mSsoWebView.onResume();
     }
 
     @Override
     public void onPause() {
-        Log_OC.d(SAML_DIALOG_TAG, "onPause");
+        Log_OC.d(TAG, "onPause");
+        mSsoWebView.onPause();
         super.onPause();
     }
     
     @Override
     public int show (FragmentTransaction transaction, String tag) {
-        Log_OC.d(SAML_DIALOG_TAG, "show (transaction)");
+        Log_OC.d(TAG, "show (transaction)");
         return super.show(transaction, tag);
     }
 
     @Override
     public void show (FragmentManager manager, String tag) {
-        Log_OC.d(SAML_DIALOG_TAG, "show (manager)");
+        Log_OC.d(TAG, "show (manager)");
         super.show(manager, tag);
     }
-
+    
 }

+ 241 - 0
src/com/owncloud/android/ui/dialog/SslUntrustedCertDialog.java

@@ -0,0 +1,241 @@
+/* ownCloud Android client application
+ *   Copyright (C) 2012-2014 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,
+ *   as published by the Free Software Foundation.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+package com.owncloud.android.ui.dialog;
+
+import java.io.IOException;
+import java.security.GeneralSecurityException;
+import java.security.cert.X509Certificate;
+
+import android.app.Activity;
+import android.app.Dialog;
+import android.net.http.SslError;
+import android.os.Bundle;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.Window;
+import android.view.View.OnClickListener;
+import android.webkit.SslErrorHandler;
+import android.widget.Button;
+
+import com.actionbarsherlock.app.SherlockDialogFragment;
+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.ui.adapter.CertificateCombinedExceptionViewAdapter;
+import com.owncloud.android.ui.adapter.SslCertificateViewAdapter;
+import com.owncloud.android.ui.adapter.SslErrorViewAdapter;
+import com.owncloud.android.ui.adapter.X509CertificateViewAdapter;
+import com.owncloud.android.utils.Log_OC;
+
+/**
+ * Dialog to show information about an untrusted certificate and allow the user
+ * to decide trust on it or not.
+ * 
+ * Abstract implementation of common functionality for different dialogs that
+ * get the information about the error and the certificate from different classes. 
+ * 
+ * @author masensio
+ * @author David A. Velasco
+ */
+public class SslUntrustedCertDialog extends SherlockDialogFragment {
+    
+    private final static String TAG = SslUntrustedCertDialog.class.getSimpleName();
+    
+    protected View mView = null;
+    protected SslErrorHandler mHandler = null;
+    protected X509Certificate m509Certificate = null;
+
+    private ErrorViewAdapter mErrorViewAdapter = null;
+    private CertificateViewAdapter mCertificateViewAdapter = null;
+    
+    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;
+    }
+    
+    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 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;
+    }
+    
+    
+    @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);    // 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
+        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 OnCertificateTrusted());
+        
+        Button cancel = (Button) mView.findViewById(R.id.cancel);
+        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);
+                if (detailsScroll.getVisibility() == View.VISIBLE) {
+                    detailsScroll.setVisibility(View.GONE);
+                    ((Button) v).setText(R.string.ssl_validator_btn_details_see);
+
+                } else {
+                    detailsScroll.setVisibility(View.VISIBLE);
+                    ((Button) v).setText(R.string.ssl_validator_btn_details_hide);
+                    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();
+    }
+    
+    private class OnCertificateNotTrusted implements OnClickListener {
+        
+        @Override
+        public void onClick(View v) {
+            getDialog().cancel();
+            if (mHandler != null) {
+                mHandler.cancel();
+            }
+            ((OnSslUntrustedCertListener)getSherlockActivity()).onCancelCertificate();
+        }
+    }
+    
+    
+    private class OnCertificateTrusted implements OnClickListener {
+
+        @Override
+        public void onClick(View v) {
+            dismiss();
+            if (mHandler != null) {
+                mHandler.proceed();
+            }
+            if (m509Certificate != null) {
+                Activity activity = getSherlockActivity();
+                try {
+                    NetworkUtils.addCertToKnownServersStore(m509Certificate, activity);   // TODO make this asynchronously, it can take some time
+                    ((OnSslUntrustedCertListener)activity).onSavedCertificate();
+    
+                } catch (GeneralSecurityException e) {
+                    ((OnSslUntrustedCertListener)activity).onFailedSavingCertificate();
+                    Log_OC.e(TAG, "Server certificate could not be saved in the known-servers trust store ", e);
+                  
+                } catch (IOException e) {
+                    ((OnSslUntrustedCertListener)activity).onFailedSavingCertificate();
+                    Log_OC.e(TAG, "Server certificate could not be saved in the known-servers trust store ", e);
+                }
+            }
+        }
+        
+    }
+    
+    
+    public interface OnSslUntrustedCertListener {
+        public void onSavedCertificate();
+        public void onFailedSavingCertificate();
+        public void onCancelCertificate();
+    }
+    
+    public interface ErrorViewAdapter {
+        void updateErrorView(View mView);
+    }
+    
+    public interface CertificateViewAdapter {
+        void updateCertificateView(View mView);
+    }
+    
+}

+ 1 - 0
src/com/owncloud/android/ui/dialog/SslValidatorDialog.java

@@ -223,6 +223,7 @@ public class SslValidatorDialog extends Dialog {
         return hex.toString();
      }    
 
+    @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));

+ 0 - 1
src/com/owncloud/android/ui/preview/PreviewImageActivity.java

@@ -23,7 +23,6 @@ import android.content.Intent;
 import android.content.IntentFilter;
 import android.content.ServiceConnection;
 import android.content.SharedPreferences;
-import android.content.res.Configuration;
 import android.os.Bundle;
 import android.os.IBinder;
 import android.preference.PreferenceManager;

+ 0 - 1
src/com/owncloud/android/ui/preview/PreviewVideoActivity.java

@@ -27,7 +27,6 @@ import android.accounts.Account;
 import android.app.AlertDialog;
 import android.content.DialogInterface;
 import android.content.Intent;
-import android.content.res.Configuration;
 import android.media.MediaPlayer;
 import android.media.MediaPlayer.OnCompletionListener;
 import android.media.MediaPlayer.OnErrorListener;