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 Exception e
= SslAnalyzer
.getRecoverableException(result
);
74 SslValidatorDialog dialog
= new SslValidatorDialog(context
, listener
);
82 * Private constructor.
84 * Instances have to be created through static {@link SslValidatorDialog#newInstance}.
86 * @param context Android context where the dialog will live
87 * @param e Exception causing the need of prompt the user about the server certificate.
88 * @param listener Object to notice when the server certificate was added to the local certificates store.
90 private SslValidatorDialog(Context context
, OnSslValidatorListener listener
) {
99 protected void onCreate(Bundle savedInstanceState
) {
100 super.onCreate(savedInstanceState
);
101 requestWindowFeature(Window
.FEATURE_NO_TITLE
);
102 mView
= getLayoutInflater().inflate(R
.layout
.ssl_validator_layout
, null
);
103 setContentView(mView
);
104 //setTitle(R.string.ssl_validator_title);
106 mView
.findViewById(R
.id
.ok
).setOnClickListener(
107 new View
.OnClickListener() {
109 public void onClick(View v
) {
113 if (mListener
!= null
)
114 mListener
.onSavedCertificate();
116 Log
.d(TAG
, "Nobody there to notify the certificate was saved");
118 } catch (Exception e
) {
120 if (mListener
!= null
)
121 mListener
.onFailedSavingCertificate();
122 Log
.e(TAG
, "Server certificate could not be saved in the known servers trust store ", e
);
127 mView
.findViewById(R
.id
.cancel
).setOnClickListener(
128 new View
.OnClickListener() {
130 public void onClick(View v
) {
137 public void updateResult(RemoteOperationResult result
) {
138 mException
= SslAnalyzer
.getRecoverableException(result
);
139 if (mException
instanceof CertPathValidatorException
) {
140 showCertificateData(((CertPathValidatorException
)mException
).getCertPath());
141 ((TextView
)mView
.findViewById(R
.id
.reason_cert_not_trusted
)).setVisibility(View
.VISIBLE
);
142 ((TextView
)mView
.findViewById(R
.id
.reason_cert_expired
)).setVisibility(View
.GONE
);
143 ((TextView
)mView
.findViewById(R
.id
.reason_cert_not_yet_valid
)).setVisibility(View
.GONE
);
144 ((TextView
)mView
.findViewById(R
.id
.reason_hostname_not_vertified
)).setVisibility(View
.GONE
);
146 } else if (mException
instanceof CertificateExpiredException
) {
147 ((TextView
)mView
.findViewById(R
.id
.reason_cert_not_trusted
)).setVisibility(View
.GONE
);
148 ((TextView
)mView
.findViewById(R
.id
.reason_cert_expired
)).setVisibility(View
.VISIBLE
);
149 ((TextView
)mView
.findViewById(R
.id
.reason_cert_not_yet_valid
)).setVisibility(View
.GONE
);
150 ((TextView
)mView
.findViewById(R
.id
.reason_hostname_not_vertified
)).setVisibility(View
.GONE
);
152 } else if (mException
instanceof CertificateNotYetValidException
) {
153 ((TextView
)mView
.findViewById(R
.id
.reason_cert_not_trusted
)).setVisibility(View
.GONE
);
154 ((TextView
)mView
.findViewById(R
.id
.reason_cert_expired
)).setVisibility(View
.GONE
);
155 ((TextView
)mView
.findViewById(R
.id
.reason_cert_not_yet_valid
)).setVisibility(View
.VISIBLE
);
156 ((TextView
)mView
.findViewById(R
.id
.reason_hostname_not_vertified
)).setVisibility(View
.GONE
);
158 } else if (mException
instanceof SSLPeerUnverifiedException
) {
159 ((TextView
)mView
.findViewById(R
.id
.reason_cert_not_trusted
)).setVisibility(View
.GONE
);
160 ((TextView
)mView
.findViewById(R
.id
.reason_cert_expired
)).setVisibility(View
.GONE
);
161 ((TextView
)mView
.findViewById(R
.id
.reason_cert_not_yet_valid
)).setVisibility(View
.GONE
);
162 ((TextView
)mView
.findViewById(R
.id
.reason_hostname_not_vertified
)).setVisibility(View
.VISIBLE
);
167 private void showCertificateData(CertPath certPath
) {
168 final List
<?
extends Certificate
> certs
= certPath
.getCertificates();
169 /*X509Certificate badCert = null;
170 if (e.getIndex() >= 0 && e.getIndex() < certs.size())
171 badCert = (X509Certificate) certs.get(e.getIndex());*/
172 if (certs
.size() > 0) {
173 X509Certificate serverCert
= (X509Certificate
) certs
.get(0);
174 String text
= serverCert
.getSubjectDN().getName();
175 text
= text
.substring(text
.indexOf(",") + 1);
176 ((TextView
)mView
.findViewById(R
.id
.issuer
)).setText(text
);
180 private void saveServerCert() throws KeyStoreException
, NoSuchAlgorithmException
, CertificateException
, IOException
{
181 // TODO be able to add certificate for any recoverable exception
182 if (mException
instanceof CertPathValidatorException
) {
183 OwnCloudClientUtils
.addCertToKnownServersStore(((CertPathValidatorException
) mException
).getCertPath().getCertificates().get(0), getContext());
188 public interface OnSslValidatorListener
{
189 public void onSavedCertificate();
190 public void onFailedSavingCertificate();