1 /* ownCloud Android client application
2 * Copyright (C) 2011 Bartek Przybylski
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 3 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 package com
.owncloud
.android
.ui
.dialog
;
20 import java
.io
.IOException
;
21 import java
.security
.KeyStoreException
;
22 import java
.security
.NoSuchAlgorithmException
;
23 import java
.security
.cert
.CertPath
;
24 import java
.security
.cert
.CertPathValidatorException
;
25 import java
.security
.cert
.Certificate
;
26 import java
.security
.cert
.CertificateException
;
27 import java
.security
.cert
.CertificateExpiredException
;
28 import java
.security
.cert
.CertificateNotYetValidException
;
29 import java
.security
.cert
.X509Certificate
;
30 import java
.util
.List
;
32 import javax
.net
.ssl
.SSLPeerUnverifiedException
;
34 import android
.app
.Dialog
;
35 import android
.content
.Context
;
36 import android
.os
.Bundle
;
37 import android
.util
.Log
;
38 import android
.view
.View
;
39 import android
.view
.Window
;
40 import android
.widget
.TextView
;
42 import com
.owncloud
.android
.R
;
43 import com
.owncloud
.android
.network
.OwnCloudClientUtils
;
44 import com
.owncloud
.android
.network
.SslAnalyzer
;
45 import com
.owncloud
.android
.operations
.RemoteOperationResult
;
48 * Dialog to request the user about a certificate that could not be validated with the certificates store in the system.
50 * @author David A. Velasco
52 public class SslValidatorDialog
extends Dialog
{
54 private final static String TAG
= SslValidatorDialog
.class.getSimpleName();
56 private OnSslValidatorListener mListener
;
57 private Exception mException
= null
;
62 * Creates a new SslValidatorDialog to ask the user if an untrusted certificate from a server should
65 * @param context Android context where the dialog will live.
66 * @param result Result of a failed remote operation.
67 * @param listener Object to notice when the server certificate was added to the local certificates store.
68 * @return A new SslValidatorDialog instance, or NULL if the operation can not be recovered
69 * by setting the certificate as reliable.
71 public static SslValidatorDialog
newInstance(Context context
, RemoteOperationResult result
, OnSslValidatorListener listener
) {
72 if (SslAnalyzer
.isRecoverable(result
)) {
73 SslValidatorDialog dialog
= new SslValidatorDialog(context
, listener
);
81 * Private constructor.
83 * Instances have to be created through static {@link SslValidatorDialog#newInstance}.
85 * @param context Android context where the dialog will live
86 * @param e Exception causing the need of prompt the user about the server certificate.
87 * @param listener Object to notice when the server certificate was added to the local certificates store.
89 private SslValidatorDialog(Context context
, OnSslValidatorListener listener
) {
98 protected void onCreate(Bundle savedInstanceState
) {
99 super.onCreate(savedInstanceState
);
100 requestWindowFeature(Window
.FEATURE_NO_TITLE
);
101 mView
= getLayoutInflater().inflate(R
.layout
.ssl_validator_layout
, null
);
102 setContentView(mView
);
103 //setTitle(R.string.ssl_validator_title);
105 mView
.findViewById(R
.id
.ok
).setOnClickListener(
106 new View
.OnClickListener() {
108 public void onClick(View v
) {
112 if (mListener
!= null
)
113 mListener
.onSavedCertificate();
115 Log
.d(TAG
, "Nobody there to notify the certificate was saved");
117 } catch (Exception e
) {
119 if (mListener
!= null
)
120 mListener
.onFailedSavingCertificate();
121 Log
.e(TAG
, "Server certificate could not be saved in the known servers trust store ", e
);
126 mView
.findViewById(R
.id
.cancel
).setOnClickListener(
127 new View
.OnClickListener() {
129 public void onClick(View v
) {
136 public void updateResult(RemoteOperationResult result
) {
137 mException
= SslAnalyzer
.getRecoverableException(result
);
138 if (mException
instanceof CertPathValidatorException
) {
139 showCertificateData(((CertPathValidatorException
)mException
).getCertPath());
140 ((TextView
)mView
.findViewById(R
.id
.reason_cert_not_trusted
)).setVisibility(View
.VISIBLE
);
141 ((TextView
)mView
.findViewById(R
.id
.reason_cert_expired
)).setVisibility(View
.GONE
);
142 ((TextView
)mView
.findViewById(R
.id
.reason_cert_not_yet_valid
)).setVisibility(View
.GONE
);
143 ((TextView
)mView
.findViewById(R
.id
.reason_hostname_not_vertified
)).setVisibility(View
.GONE
);
145 } else if (mException
instanceof CertificateExpiredException
) {
146 ((TextView
)mView
.findViewById(R
.id
.reason_cert_not_trusted
)).setVisibility(View
.GONE
);
147 ((TextView
)mView
.findViewById(R
.id
.reason_cert_expired
)).setVisibility(View
.VISIBLE
);
148 ((TextView
)mView
.findViewById(R
.id
.reason_cert_not_yet_valid
)).setVisibility(View
.GONE
);
149 ((TextView
)mView
.findViewById(R
.id
.reason_hostname_not_vertified
)).setVisibility(View
.GONE
);
151 } else if (mException
instanceof CertificateNotYetValidException
) {
152 ((TextView
)mView
.findViewById(R
.id
.reason_cert_not_trusted
)).setVisibility(View
.GONE
);
153 ((TextView
)mView
.findViewById(R
.id
.reason_cert_expired
)).setVisibility(View
.GONE
);
154 ((TextView
)mView
.findViewById(R
.id
.reason_cert_not_yet_valid
)).setVisibility(View
.VISIBLE
);
155 ((TextView
)mView
.findViewById(R
.id
.reason_hostname_not_vertified
)).setVisibility(View
.GONE
);
157 } else if (mException
instanceof SSLPeerUnverifiedException
) {
158 ((TextView
)mView
.findViewById(R
.id
.reason_cert_not_trusted
)).setVisibility(View
.GONE
);
159 ((TextView
)mView
.findViewById(R
.id
.reason_cert_expired
)).setVisibility(View
.GONE
);
160 ((TextView
)mView
.findViewById(R
.id
.reason_cert_not_yet_valid
)).setVisibility(View
.GONE
);
161 ((TextView
)mView
.findViewById(R
.id
.reason_hostname_not_vertified
)).setVisibility(View
.VISIBLE
);
166 private void showCertificateData(CertPath certPath
) {
167 final List
<?
extends Certificate
> certs
= certPath
.getCertificates();
168 /*X509Certificate badCert = null;
169 if (e.getIndex() >= 0 && e.getIndex() < certs.size())
170 badCert = (X509Certificate) certs.get(e.getIndex());*/
171 if (certs
.size() > 0) {
172 X509Certificate serverCert
= (X509Certificate
) certs
.get(0);
173 String text
= serverCert
.getSubjectDN().getName();
174 text
= text
.substring(text
.indexOf(",") + 1);
175 ((TextView
)mView
.findViewById(R
.id
.issuer
)).setText(text
);
179 private void saveServerCert() throws KeyStoreException
, NoSuchAlgorithmException
, CertificateException
, IOException
{
180 // TODO be able to add certificate for any recoverable exception
181 if (mException
instanceof CertPathValidatorException
) {
182 OwnCloudClientUtils
.addCertToKnownServersStore(((CertPathValidatorException
) mException
).getCertPath().getCertificates().get(0), getContext());
187 public interface OnSslValidatorListener
{
188 public void onSavedCertificate();
189 public void onFailedSavingCertificate();