diff --git a/CMakeLists.txt b/CMakeLists.txt
index 375ba98372..2ad5f2b2d1 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -142,6 +142,7 @@ endif()
if (USE_NEON)
find_package(Neon REQUIRED)
endif(USE_NEON)
+find_package(OpenSSL)
if(NOT TOKEN_AUTH_ONLY)
if (Qt5Core_DIR)
diff --git a/csync/src/CMakeLists.txt b/csync/src/CMakeLists.txt
index 77b8e87268..91f23070fb 100644
--- a/csync/src/CMakeLists.txt
+++ b/csync/src/CMakeLists.txt
@@ -68,6 +68,7 @@ if(USE_NEON)
)
list(APPEND CSYNC_LINK_LIBRARIES
${NEON_LIBRARIES}
+ ${CRYPTO_LIBRARY}
)
add_definitions(-DUSE_NEON)
endif(USE_NEON)
@@ -93,6 +94,8 @@ include_directories(
${CSYNC_PRIVATE_INCLUDE_DIRS}
)
+FIND_LIBRARY(CRYPTO_LIBRARY NAMES crypto)
+
add_library(${CSYNC_LIBRARY} SHARED ${csync_SRCS})
#add_library(${CSYNC_LIBRARY}_static STATIC ${csync_SRCS})
diff --git a/csync/src/csync.h b/csync/src/csync.h
index e16fd39e01..f8c58b4b23 100644
--- a/csync/src/csync.h
+++ b/csync/src/csync.h
@@ -46,6 +46,11 @@
extern "C" {
#endif
+struct csync_client_certs_s {
+ char *certificatePath;
+ char *certificatePasswd;
+};
+
/**
* Instruction enum. In the file traversal structure, it describes
* the csync state of a file.
diff --git a/csync/src/csync_owncloud.c b/csync/src/csync_owncloud.c
index 14b6d8822a..834cec0782 100644
--- a/csync/src/csync_owncloud.c
+++ b/csync/src/csync_owncloud.c
@@ -385,6 +385,7 @@ int dav_connect(CSYNC *csyncCtx, const char *base_url) {
unsigned int port = 0;
int proxystate = -1;
csync_owncloud_ctx_t *ctx = csyncCtx->owncloud_context;
+ struct csync_client_certs_s* clientCerts = csyncCtx->clientCerts;
if (ctx->_connected) {
return 0;
@@ -448,6 +449,29 @@ int dav_connect(CSYNC *csyncCtx, const char *base_url) {
goto out;
}
+ if(clientCerts != NULL) {
+ ne_ssl_client_cert *clicert;
+
+ DEBUG_WEBDAV("dav_connect: certificatePath and certificatePasswd are set, so we use it" );
+ DEBUG_WEBDAV(" with certificatePath: %s", clientCerts->certificatePath );
+ DEBUG_WEBDAV(" with certificatePasswd: %s", clientCerts->certificatePasswd );
+ clicert = ne_ssl_clicert_read ( clientCerts->certificatePath );
+ if ( clicert == NULL ) {
+ DEBUG_WEBDAV ( "Error read certificate : %s", ne_get_error ( ctx->dav_session.ctx ) );
+ } else {
+ if ( ne_ssl_clicert_encrypted ( clicert ) ) {
+ int rtn = ne_ssl_clicert_decrypt ( clicert, clientCerts->certificatePasswd );
+ if ( !rtn ) {
+ DEBUG_WEBDAV ( "Certificate was deciphered successfully." );
+ ne_ssl_set_clicert ( ctx->dav_session.ctx, clicert );
+ } else {
+ DEBUG_WEBDAV ( "Errors while deciphering certificate: %s", ne_get_error ( ctx->dav_session.ctx ) );
+ }
+ }
+ }
+ } else {
+ DEBUG_WEBDAV("dav_connect: error with csync_client_certs_s* clientCerts");
+ }
ne_ssl_trust_default_ca( ctx->dav_session.ctx );
ne_ssl_set_verify( ctx->dav_session.ctx, ssl_callback_by_neon, ctx);
}
@@ -478,6 +502,7 @@ out:
return rc;
}
+
char *owncloud_error_string(CSYNC* ctx)
{
return ctx->owncloud_context->dav_session.error_string;
@@ -505,7 +530,6 @@ int owncloud_commit(CSYNC* ctx) {
SAFE_FREE( ctx->owncloud_context->dav_session.pwd );
SAFE_FREE( ctx->owncloud_context->dav_session.session_key);
SAFE_FREE( ctx->owncloud_context->dav_session.error_string );
-
return 0;
}
@@ -513,6 +537,12 @@ void owncloud_destroy(CSYNC* ctx)
{
owncloud_commit(ctx);
SAFE_FREE(ctx->owncloud_context);
+
+ SAFE_FREE(ctx->clientCerts->certificatePasswd);
+ SAFE_FREE(ctx->clientCerts->certificatePath);
+ SAFE_FREE(ctx->clientCerts);
+ ctx->clientCerts = NULL;
+
ctx->owncloud_context = 0;
ne_sock_exit();
}
@@ -547,12 +577,28 @@ int owncloud_set_property(CSYNC* ctx, const char *key, void *data) {
if( c_streq(key, "redirect_callback")) {
if (data) {
csync_owncloud_redirect_callback_t* cb_wrapper = data;
-
ctx->owncloud_context->dav_session.redir_callback = *cb_wrapper;
} else {
ctx->owncloud_context->dav_session.redir_callback = NULL;
}
}
+ if( c_streq(key, "SSLClientCerts")) {
+ if(ctx->clientCerts != NULL) {
+ SAFE_FREE(ctx->clientCerts->certificatePasswd);
+ SAFE_FREE(ctx->clientCerts->certificatePath);
+ SAFE_FREE(ctx->clientCerts);
+ ctx->clientCerts = NULL;
+ }
+ if (data) {
+ struct csync_client_certs_s* clientCerts = (struct csync_client_certs_s*) data;
+ struct csync_client_certs_s* newCerts = c_malloc(sizeof(struct csync_client_certs_s));
+ newCerts->certificatePath = c_strdup(clientCerts->certificatePath);
+ newCerts->certificatePasswd = c_strdup(clientCerts->certificatePasswd);
+ ctx->clientCerts = newCerts;
+ } else {
+ DEBUG_WEBDAV("error: in owncloud_set_property for 'SSLClientCerts'" );
+ }
+ }
return -1;
}
@@ -567,3 +613,4 @@ void owncloud_init(CSYNC* ctx) {
}
/* vim: set ts=4 sw=4 et cindent: */
+
diff --git a/csync/src/csync_owncloud_private.h b/csync/src/csync_owncloud_private.h
index c74ee4e0c1..03cd73a8e4 100644
--- a/csync/src/csync_owncloud_private.h
+++ b/csync/src/csync_owncloud_private.h
@@ -96,6 +96,7 @@ struct csync_owncloud_ctx_s {
int _connected; /* flag to indicate if a connection exists, ie.
the dav_session is valid */
};
+
typedef struct csync_owncloud_ctx_s csync_owncloud_ctx_t;
//typedef csync_owncloud_ctx_t* csync_owncloud_ctx_p;
diff --git a/csync/src/csync_private.h b/csync/src/csync_private.h
index 6e9d42b8f0..7a4e2a5eb3 100644
--- a/csync/src/csync_private.h
+++ b/csync/src/csync_private.h
@@ -79,6 +79,7 @@ typedef struct csync_file_stat_s csync_file_stat_t;
struct csync_owncloud_ctx_s; // csync_owncloud.c
+
/**
* @brief csync public structure
*/
@@ -96,6 +97,9 @@ struct csync_s {
} callbacks;
c_strlist_t *excludes;
+ // needed for SSL client certificate support
+ struct csync_client_certs_s *clientCerts;
+
struct {
char *file;
sqlite3 *db;
diff --git a/src/3rdparty/certificates/p12topem.cpp b/src/3rdparty/certificates/p12topem.cpp
new file mode 100644
index 0000000000..75e736a7ab
--- /dev/null
+++ b/src/3rdparty/certificates/p12topem.cpp
@@ -0,0 +1,114 @@
+/*
+ * Copyright (C) by Pierre MOREAU
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * 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.
+ */
+
+/**
+ * \file p12topem.cpp
+ * \brief Static library to convert p12 to pem
+ * \author Pierre MOREAU
+ * \version 1.0.0
+ * \date 09 January 2014
+ */
+
+#include "p12topem.h"
+
+/**
+ * \fn string x509ToString (BIO)
+ * \brief Return string from BIO SSL
+ * \param BIO o PEM_write_BIO_...
+ * \return string PEM
+ */
+string x509ToString(BIO *o) {
+ int len = 0;
+ BUF_MEM *bptr;
+ void* data;
+ string ret = "";
+
+ BIO_get_mem_ptr(o, &bptr);
+ len = bptr->length;
+ data = calloc(len+10, sizeof(char));
+ BIO_read(o, data, len);
+ ret = strdup((char*)data);
+ free(data);
+
+ return ret;
+}
+
+/**
+ * \fn resultP12ToPem p12ToPem (string, string)
+ * \brief Convert P12 to PEM
+ * \param string p12File Path to P12 file
+ * \param string p12Passwd Password to open P12 file
+ * \return result (bool ReturnCode, Int ErrorCode, String Comment, String PrivateKey, String Certificate)
+ */
+resultP12ToPem p12ToPem(string p12File, string p12Passwd) {
+ FILE *fp;
+ PKCS12 *p12 = NULL;
+ EVP_PKEY *pkey = NULL;
+ X509 *cert = NULL;
+ STACK_OF(X509) *ca = NULL;
+
+ BIO *o = BIO_new(BIO_s_mem());
+
+ string privateKey = "";
+ string certificate = "";
+
+ resultP12ToPem ret;
+ ret.ReturnCode = false;
+ ret.ErrorCode = 0;
+ ret.Comment = "";
+ ret.PrivateKey = "";
+ ret.Certificate = "";
+
+ SSLeay_add_all_algorithms();
+ ERR_load_crypto_strings();
+ if(!(fp = fopen(p12File.c_str(), "rb"))) {
+ ret.ErrorCode = 1;
+ ret.Comment = strerror(errno);
+ return ret;
+ }
+
+ p12 = d2i_PKCS12_fp(fp, &p12);
+ fclose (fp);
+
+ if (!p12) {
+ ret.ErrorCode = 2;
+ ret.Comment = "Unable to open PKCS#12 file";
+ return ret;
+ }
+ if (!PKCS12_parse(p12, p12Passwd.c_str(), &pkey, &cert, &ca)) {
+ ret.ErrorCode = 3;
+ ret.Comment = "Unable to parse PKCS#12 file (wrong password ?)";
+ return ret;
+ }
+ PKCS12_free(p12);
+
+ if (!(pkey && cert)) {
+ ret.ErrorCode = 4;
+ ret.Comment = "Certificate and/or key file doesn't exists";
+ } else {
+ PEM_write_bio_PrivateKey(o, pkey, 0, 0, 0, NULL, 0);
+ privateKey = x509ToString(o);
+
+ PEM_write_bio_X509(o, cert);
+ certificate = x509ToString(o);
+
+ BIO_free(o);
+
+ ret.ReturnCode = true;
+ ret.ErrorCode = 0;
+ ret.Comment = "All is fine";
+ ret.PrivateKey = privateKey;
+ ret.Certificate = certificate;
+ }
+ return ret;
+}
diff --git a/src/3rdparty/certificates/p12topem.h b/src/3rdparty/certificates/p12topem.h
new file mode 100644
index 0000000000..0798a907ff
--- /dev/null
+++ b/src/3rdparty/certificates/p12topem.h
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) by Pierre MOREAU
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * 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.
+ */
+
+#ifndef P12TOPEM_H
+#define P12TOPEM_H
+
+/**
+ * \file p12topem.h
+ * \brief Static library to convert p12 to pem
+ * \author Pierre MOREAU
+ * \version 1.0.0
+ * \date 09 January 2014
+ */
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+using namespace std;
+
+/**
+ * \struct resultP12ToPem p12topem.h
+ */
+struct resultP12ToPem {
+ bool ReturnCode;
+ int ErrorCode;
+ string Comment;
+ string PrivateKey;
+ string Certificate;
+};
+
+/**
+ * \brief Return string from BIO SSL
+ * \param BIO o PEM_write_BIO_...
+ * \return string PEM
+ */
+string x509ToString(BIO *o);
+
+/**
+ * \brief Convert P12 to PEM
+ * \param string p12File Path to P12 file
+ * \param string p12Passwd Password to open P12 file
+ * \return result (bool ReturnCode, Int ErrorCode, String Comment, String PrivateKey, String Certificate)
+ */
+resultP12ToPem p12ToPem(string p12File, string p12Passwd);
+
+#endif /* P12TOPEM_H */
+
diff --git a/src/cmd/cmd.cpp b/src/cmd/cmd.cpp
index 463fe8f39a..1e7c3dd53d 100644
--- a/src/cmd/cmd.cpp
+++ b/src/cmd/cmd.cpp
@@ -110,7 +110,7 @@ QString queryPassword(const QString &user)
class HttpCredentialsText : public HttpCredentials {
public:
HttpCredentialsText(const QString& user, const QString& password)
- : HttpCredentials(user, password),
+ : HttpCredentials(user, password, "", "", ""), // FIXME: not working with client certs yet (qknight)
_sslTrusted(false)
{}
diff --git a/src/gui/CMakeLists.txt b/src/gui/CMakeLists.txt
index 7379920c14..8919b19501 100644
--- a/src/gui/CMakeLists.txt
+++ b/src/gui/CMakeLists.txt
@@ -24,6 +24,8 @@ set(client_UI
settingsdialog.ui
sharedialog.ui
sslerrordialog.ui
+ owncloudsetuppage.ui
+ addcertificatedialog.ui
wizard/owncloudadvancedsetuppage.ui
wizard/owncloudhttpcredspage.ui
wizard/owncloudsetupnocredspage.ui
@@ -59,6 +61,7 @@ set(client_SRCS
accountmigrator.cpp
quotainfo.cpp
accountstate.cpp
+ addcertificatedialog.cpp
wizard/abstractcredswizardpage.cpp
wizard/owncloudadvancedsetuppage.cpp
wizard/owncloudhttpcredspage.cpp
@@ -106,6 +109,7 @@ set(3rdparty_SRC
../3rdparty/qtsingleapplication/qtlocalpeer.cpp
../3rdparty/qtsingleapplication/qtsingleapplication.cpp
../3rdparty/qtsingleapplication/qtsinglecoreapplication.cpp
+ ../3rdparty/certificates/p12topem.cpp
)
if (APPLE)
@@ -251,6 +255,7 @@ install(TARGETS ${APPLICATION_EXECUTABLE}
BUNDLE DESTINATION "."
)
+
# FIXME: The following lines are dup in src/gui and src/cmd because it needs to be done after both are installed
#FIXME: find a nice solution to make the second if(BUILD_OWNCLOUD_OSX_BUNDLE) unnecessary
# currently it needs to be done because the code right above needs to be executed no matter
diff --git a/src/gui/addcertificatedialog.cpp b/src/gui/addcertificatedialog.cpp
new file mode 100644
index 0000000000..030658af07
--- /dev/null
+++ b/src/gui/addcertificatedialog.cpp
@@ -0,0 +1,49 @@
+#include "ui_addcertificatedialog.h"
+#include "addcertificatedialog.h"
+#include
+#include
+
+
+namespace OCC {
+AddCertificateDialog::AddCertificateDialog(QWidget *parent) :
+ QDialog(parent),
+ ui(new Ui::AddCertificateDialog)
+{
+ ui->setupUi(this);
+ ui->labelErrorCertif->setText("");
+}
+
+AddCertificateDialog::~AddCertificateDialog()
+{
+ delete ui;
+}
+
+void AddCertificateDialog::on_pushButtonBrowseCertificate_clicked()
+{
+ QString fileName = QFileDialog::getOpenFileName(this, tr("Select a certificate"), "", tr("Certificate files (*.p12 *.pfx)"));
+ ui->lineEditCertificatePath->setText(fileName);
+}
+
+QString AddCertificateDialog::getCertificatePath()
+{
+ return ui->lineEditCertificatePath->text();
+}
+
+QString AddCertificateDialog::getCertificatePasswd()
+{
+ return ui->lineEditPWDCertificate->text();
+}
+
+void AddCertificateDialog::showErrorMessage(const QString message)
+{
+ ui->labelErrorCertif->setText(message);
+}
+
+void AddCertificateDialog::Reinit()
+{
+ ui->labelErrorCertif->setText("");
+ ui->lineEditCertificatePath->setText("");
+ ui->lineEditPWDCertificate->setText("");
+}
+
+}
diff --git a/src/gui/addcertificatedialog.h b/src/gui/addcertificatedialog.h
new file mode 100644
index 0000000000..9bcd57a917
--- /dev/null
+++ b/src/gui/addcertificatedialog.h
@@ -0,0 +1,35 @@
+#ifndef ADDCERTIFICATEDIALOG_H
+#define ADDCERTIFICATEDIALOG_H
+
+#include
+#include
+
+namespace OCC {
+
+namespace Ui {
+class AddCertificateDialog;
+}
+
+class AddCertificateDialog : public QDialog
+{
+ Q_OBJECT
+
+public:
+ explicit AddCertificateDialog(QWidget *parent = 0);
+ ~AddCertificateDialog();
+ QString getCertificatePath();
+ QString getCertificatePasswd();
+ void showErrorMessage(const QString message);
+ void Reinit();
+
+private slots:
+ void on_pushButtonBrowseCertificate_clicked();
+
+private:
+ Ui::AddCertificateDialog *ui;
+
+};
+
+}//End namespace OCC
+
+#endif // ADDCERTIFICATEDIALOG_H
diff --git a/src/gui/addcertificatedialog.ui b/src/gui/addcertificatedialog.ui
new file mode 100644
index 0000000000..341a2a6040
--- /dev/null
+++ b/src/gui/addcertificatedialog.ui
@@ -0,0 +1,220 @@
+
+
+ OCC::AddCertificateDialog
+
+
+ Qt::ApplicationModal
+
+
+
+ 0
+ 0
+ 400
+ 350
+
+
+
+
+ 400
+ 350
+
+
+
+
+ 400
+ 350
+
+
+
+ SSL client certificate authentication
+
+
+
+
+ 30
+ 280
+ 341
+ 32
+
+
+
+ Qt::Horizontal
+
+
+ QDialogButtonBox::Cancel|QDialogButtonBox::Ok
+
+
+
+
+
+ 20
+ 100
+ 141
+ 16
+
+
+
+ Certificate :
+
+
+
+
+
+ 20
+ 120
+ 291
+ 21
+
+
+
+
+
+
+
+
+
+ 320
+ 120
+ 71
+ 21
+
+
+
+ Browse...
+
+
+
+
+
+ 20
+ 160
+ 181
+ 16
+
+
+
+ Certificate password :
+
+
+
+
+
+ 20
+ 180
+ 291
+ 21
+
+
+
+
+
+
+ QLineEdit::Password
+
+
+
+
+
+ 20
+ 30
+ 341
+ 41
+
+
+
+ This server probably requires a SSL client certificate.
+
+
+ true
+
+
+
+
+
+ 20
+ 220
+ 361
+ 51
+
+
+
+
+
+
+
+
+ 231
+ 23
+ 12
+
+
+
+
+
+
+
+
+ 231
+ 23
+ 12
+
+
+
+
+
+
+
+
+ 127
+ 127
+ 127
+
+
+
+
+
+
+
+
+
+
+ true
+
+
+
+
+
+
+ buttonBox
+ accepted()
+ OCC::AddCertificateDialog
+ accept()
+
+
+ 248
+ 254
+
+
+ 157
+ 274
+
+
+
+
+ buttonBox
+ rejected()
+ OCC::AddCertificateDialog
+ reject()
+
+
+ 316
+ 260
+
+
+ 286
+ 274
+
+
+
+
+
diff --git a/src/gui/folder.cpp b/src/gui/folder.cpp
index 526f604129..e60600c3d5 100644
--- a/src/gui/folder.cpp
+++ b/src/gui/folder.cpp
@@ -301,6 +301,7 @@ void Folder::slotRunEtagJob()
_requestEtagJob = new RequestEtagJob(account, remotePath(), this);
// check if the etag is different
QObject::connect(_requestEtagJob, SIGNAL(etagRetreived(QString)), this, SLOT(etagRetreived(QString)));
+ QObject::connect(_requestEtagJob, SIGNAL(networkError(QNetworkReply*)), this, SLOT(slotNetworkUnavailable()));
FolderMan::instance()->slotScheduleETagJob(alias(), _requestEtagJob);
// The _requestEtagJob is auto deleting itself on finish. Our guard pointer _requestEtagJob will then be null.
}
diff --git a/src/gui/wizard/owncloudhttpcredspage.cpp b/src/gui/wizard/owncloudhttpcredspage.cpp
index c7d1d0264b..4bca38aaf6 100644
--- a/src/gui/wizard/owncloudhttpcredspage.cpp
+++ b/src/gui/wizard/owncloudhttpcredspage.cpp
@@ -26,7 +26,7 @@
namespace OCC
{
-OwncloudHttpCredsPage::OwncloudHttpCredsPage()
+OwncloudHttpCredsPage::OwncloudHttpCredsPage(QWidget* parent)
: AbstractCredentialsWizardPage(),
_ui(),
_connected(false),
@@ -36,6 +36,10 @@ OwncloudHttpCredsPage::OwncloudHttpCredsPage()
{
_ui.setupUi(this);
+ if(parent){
+ _ocWizard = qobject_cast(parent);
+ }
+
registerField( QLatin1String("OCUser*"), _ui.leUsername);
registerField( QLatin1String("OCPasswd*"), _ui.lePassword);
@@ -148,7 +152,8 @@ void OwncloudHttpCredsPage::setErrorString(const QString& err)
AbstractCredentials* OwncloudHttpCredsPage::getCredentials() const
{
- return new HttpCredentialsGui(_ui.leUsername->text(), _ui.lePassword->text());
+ QDateTime now = QDateTime::currentDateTime();
+ return new HttpCredentialsGui(_ui.leUsername->text(), _ui.lePassword->text(), _ocWizard->ownCloudCertificatePath, now.toString(QLatin1String("yyyy-MM-dd")), _ocWizard->ownCloudCertificatePasswd);
}
void OwncloudHttpCredsPage::setConfigExists(bool config)
diff --git a/src/gui/wizard/owncloudhttpcredspage.h b/src/gui/wizard/owncloudhttpcredspage.h
index 07e2d45a47..2a2de53540 100644
--- a/src/gui/wizard/owncloudhttpcredspage.h
+++ b/src/gui/wizard/owncloudhttpcredspage.h
@@ -17,6 +17,7 @@
#define MIRALL_OWNCLOUD_HTTP_CREDS_PAGE_H
#include "wizard/abstractcredswizardpage.h"
+#include "wizard/owncloudwizard.h"
#include "ui_owncloudhttpcredspage.h"
@@ -28,7 +29,7 @@ class OwncloudHttpCredsPage : public AbstractCredentialsWizardPage
{
Q_OBJECT
public:
- OwncloudHttpCredsPage();
+ OwncloudHttpCredsPage(QWidget* parent);
AbstractCredentials* getCredentials() const Q_DECL_OVERRIDE;
@@ -53,6 +54,7 @@ private:
bool _checking;
bool _configExists;
QProgressIndicator* _progressIndi;
+ OwncloudWizard* _ocWizard;
};
} // namespace OCC
diff --git a/src/gui/wizard/owncloudsetuppage.cpp b/src/gui/wizard/owncloudsetuppage.cpp
index f7733cb2a8..25571032dc 100644
--- a/src/gui/wizard/owncloudsetuppage.cpp
+++ b/src/gui/wizard/owncloudsetuppage.cpp
@@ -19,17 +19,21 @@
#include
#include
#include
+#include
+#include
#include "QProgressIndicator.h"
#include "wizard/owncloudwizardcommon.h"
#include "wizard/owncloudsetuppage.h"
+#include "../3rdparty/certificates/p12topem.h"
#include "theme.h"
+#include "account.h"
namespace OCC
{
-OwncloudSetupPage::OwncloudSetupPage()
+OwncloudSetupPage::OwncloudSetupPage(QWidget *parent)
: QWizardPage(),
_ui(),
_oCUrl(),
@@ -58,6 +62,10 @@ OwncloudSetupPage::OwncloudSetupPage()
connect(_ui.leUrl, SIGNAL(textChanged(QString)), SLOT(slotUrlChanged(QString)));
connect(_ui.leUrl, SIGNAL(editingFinished()), SLOT(slotUrlEditFinished()));
+
+ addCertDial = new AddCertificateDialog(this);
+ _ocWizard = qobject_cast(parent);
+ connect(_ocWizard,SIGNAL(needCertificate()),this,SLOT(slotAskSSLClientCertificate()));
}
void OwncloudSetupPage::setServerUrl( const QString& newUrl )
@@ -228,14 +236,18 @@ void OwncloudSetupPage::setErrorString( const QString& err, bool retryHTTPonly )
_ui.errorLabel->setVisible(false);
} else {
if (retryHTTPonly) {
- QString msg = tr("Could not connect securely:
%1
Do you want to connect unencrypted instead (not recommended)?
").arg(err);
- QString title = tr("Connection failed");
- if (QMessageBox::question(this, title, msg, QMessageBox::Yes, QMessageBox::No) == QMessageBox::Yes) {
- QUrl url(_ui.leUrl->text());
- url.setScheme("http");
- _ui.leUrl->setText(url.toString());
- // skip ahead to next page, since the user would expect us to retry automatically
- wizard()->next();
+ if (err.contains("SSL handshake failed", Qt::CaseInsensitive)) {
+ slotAskSSLClientCertificate();
+ } else {
+ QString msg = tr("Could not connect securely:
%1
Do you want to connect unencrypted instead (not recommended)?
").arg(err);
+ QString title = tr("Connection failed");
+ if (QMessageBox::question(this, title, msg, QMessageBox::Yes, QMessageBox::No) == QMessageBox::Yes) {
+ QUrl url(_ui.leUrl->text());
+ url.setScheme("http");
+ _ui.leUrl->setText(url.toString());
+ // skip ahead to next page, since the user would expect us to retry automatically
+ wizard()->next();
+ }
}
}
@@ -269,4 +281,76 @@ void OwncloudSetupPage::setConfigExists( bool config )
}
}
+
+void OwncloudSetupPage::slotAskSSLClientCertificate()
+{
+ addCertDial->show();
+ connect(addCertDial, SIGNAL(accepted()),this,SLOT(slotCertificateAccepted()));
+}
+
+//called during the validation of the client certificate.
+void OwncloudSetupPage::slotCertificateAccepted()
+{
+ QSslCertificate sslCertificate;
+
+ resultP12ToPem certif = p12ToPem(addCertDial->getCertificatePath().toStdString() , addCertDial->getCertificatePasswd().toStdString());
+ if(certif.ReturnCode){
+ QString s = QString::fromStdString(certif.Certificate);
+ QByteArray ba = s.toLocal8Bit();
+
+ QList sslCertificateList = QSslCertificate::fromData(ba, QSsl::Pem);
+ sslCertificate = sslCertificateList.takeAt(0);
+
+ this->_ocWizard->ownCloudCertificate = ba;
+ this->_ocWizard->ownCloudPrivateKey = certif.PrivateKey.c_str();
+ this->_ocWizard->ownCloudCertificatePath = addCertDial->getCertificatePath();
+ this->_ocWizard->ownCloudCertificatePasswd = addCertDial->getCertificatePasswd();
+
+ //FIXME qknight: hacky code ahead
+ AccountPtr acc = this->_ocWizard->account();
+ acc->setCertificate(_ocWizard->ownCloudCertificate, _ocWizard->ownCloudPrivateKey);
+
+ QList qba = sslCertificate.subjectInfoAttributes();
+ QString _DN = "";
+ QString _C,_ST, _L, _O, _OU, _CN, _emailAddress;
+ foreach(QByteArray qa, qba)
+ {
+ if(strcmp(qa.data(),"C")==0){
+ _C="/"+QString(qa)+"="+sslCertificate.subjectInfo(qa).join('/');
+ }
+ else if(strcmp(qa.data(),"ST")==0){
+ _ST="/"+QString(qa)+"="+sslCertificate.subjectInfo(qa).join('/');
+ }
+ else if(strcmp(qa.data(),"L")==0){
+ _L="/"+QString(qa)+"="+sslCertificate.subjectInfo(qa).join('/');
+ }
+ else if(strcmp(qa.data(),"O")==0){
+ _O="/"+QString(qa)+"="+sslCertificate.subjectInfo(qa).join('/');
+ }
+ else if(strcmp(qa.data(),"OU")==0){
+ _OU="/"+QString(qa)+"="+sslCertificate.subjectInfo(qa).join('/');
+ }
+ else if(strcmp(qa.data(),"CN")==0){
+ _CN="/"+QString(qa)+"="+sslCertificate.subjectInfo(qa).join('/');
+ }
+ else if(strcmp(qa.data(),"emailAddress")==0){
+ _emailAddress="/"+QString(qa)+"="+sslCertificate.subjectInfo(qa).join('/');
+ }
+ }
+ _DN += _C+_ST+_L+_O+_OU+_CN+_emailAddress;
+ addCertDial->Reinit();
+ validatePage();
+ } else {
+ QString message;
+ message = certif.Comment.c_str();
+ addCertDial->showErrorMessage(message);
+ addCertDial->show();
+ }
+}
+
+OwncloudSetupPage::~OwncloudSetupPage()
+{
+ delete addCertDial;
+}
+
} // namespace OCC
diff --git a/src/gui/wizard/owncloudsetuppage.h b/src/gui/wizard/owncloudsetuppage.h
index 5385b2d09a..2576cf3621 100644
--- a/src/gui/wizard/owncloudsetuppage.h
+++ b/src/gui/wizard/owncloudsetuppage.h
@@ -19,6 +19,10 @@
#include
#include "wizard/owncloudwizardcommon.h"
+#include "wizard/owncloudwizard.h"
+
+#include "../addcertificatedialog.h"
+
#include "ui_owncloudsetupnocredspage.h"
class QLabel;
@@ -31,7 +35,8 @@ class OwncloudSetupPage: public QWizardPage
{
Q_OBJECT
public:
- OwncloudSetupPage();
+ OwncloudSetupPage(QWidget *parent=0);
+ ~OwncloudSetupPage();
virtual bool isComplete() const Q_DECL_OVERRIDE;
virtual void initializePage() Q_DECL_OVERRIDE;
@@ -50,6 +55,8 @@ public slots:
void setConfigExists( bool );
void startSpinner();
void stopSpinner();
+ void slotAskSSLClientCertificate();
+ void slotCertificateAccepted();
protected slots:
void slotUrlChanged(const QString&);
@@ -64,14 +71,20 @@ private:
bool urlHasChanged();
Ui_OwncloudSetupPage _ui;
+
QString _oCUrl;
QString _ocUser;
bool _authTypeKnown;
bool _checking;
+ bool _configExists;
+ bool _multipleFoldersExist;
WizardCommon::AuthType _authType;
QProgressIndicator* _progressIndi;
+ QButtonGroup* _selectiveSyncButtons;
QString _remoteFolder;
+ AddCertificateDialog* addCertDial;
+ OwncloudWizard* _ocWizard;
};
} // namespace OCC
diff --git a/src/gui/wizard/owncloudwizard.cpp b/src/gui/wizard/owncloudwizard.cpp
index 6e04c17e85..1964000987 100644
--- a/src/gui/wizard/owncloudwizard.cpp
+++ b/src/gui/wizard/owncloudwizard.cpp
@@ -37,8 +37,8 @@ namespace OCC
OwncloudWizard::OwncloudWizard(QWidget *parent)
: QWizard(parent),
_account(0),
- _setupPage(new OwncloudSetupPage),
- _httpCredsPage(new OwncloudHttpCredsPage),
+ _setupPage(new OwncloudSetupPage(this)),
+ _httpCredsPage(new OwncloudHttpCredsPage(this)),
_shibbolethCredsPage(new OwncloudShibbolethCredsPage),
_advancedSetupPage(new OwncloudAdvancedSetupPage),
_resultPage(new OwncloudWizardResultPage),
@@ -238,5 +238,11 @@ AbstractCredentials* OwncloudWizard::getCredentials() const
return 0;
}
+// outputs the signal needed to authenticate a certificate
+void OwncloudWizard::raiseCertificatePopup()
+{
+ emit needCertificate();
+}
+
} // end namespace
diff --git a/src/gui/wizard/owncloudwizard.h b/src/gui/wizard/owncloudwizard.h
index ebfa356967..06515a2403 100644
--- a/src/gui/wizard/owncloudwizard.h
+++ b/src/gui/wizard/owncloudwizard.h
@@ -61,6 +61,12 @@ public:
void successfulStep();
AbstractCredentials* getCredentials() const;
+ void raiseCertificatePopup();
+ QByteArray ownCloudCertificate;
+ QString ownCloudPrivateKey;
+ QString ownCloudCertificatePath;
+ QString ownCloudCertificatePasswd;
+
public slots:
void setAuthType(WizardCommon::AuthType type);
void setRemoteFolder( const QString& );
@@ -75,6 +81,7 @@ signals:
// make sure to connect to this, rather than finished(int)!!
void basicSetupFinished( int );
void skipFolderConfiguration();
+ void needCertificate();
private:
AccountPtr _account;
diff --git a/src/libsync/CMakeLists.txt b/src/libsync/CMakeLists.txt
index 7aac1f8496..80d47033ba 100644
--- a/src/libsync/CMakeLists.txt
+++ b/src/libsync/CMakeLists.txt
@@ -66,6 +66,7 @@ set(libsync_SRCS
creds/http/httpconfigfile.cpp
creds/credentialscommon.cpp
../3rdparty/qjson/json.cpp
+ ../3rdparty/certificates/p12topem.cpp
)
if(TOKEN_AUTH_ONLY)
set (libsync_SRCS
@@ -122,6 +123,7 @@ list(APPEND libsync_LINK_TARGETS
${QT_LIBRARIES}
ocsync
${OS_SPECIFIC_LINK_LIBRARIES}
+ ${OPENSSL_LIBRARIES}
)
if(QTKEYCHAIN_FOUND OR QT5KEYCHAIN_FOUND)
diff --git a/src/libsync/account.cpp b/src/libsync/account.cpp
index 79fdb74a35..d3c1a870e6 100644
--- a/src/libsync/account.cpp
+++ b/src/libsync/account.cpp
@@ -20,6 +20,7 @@
#include "owncloudtheme.h"
#include "creds/abstractcredentials.h"
#include "creds/credentialsfactory.h"
+#include "../3rdparty/certificates/p12topem.h"
#include
#include
@@ -29,8 +30,8 @@
#include
#include
#include
-
#include
+#include
namespace OCC {
@@ -294,6 +295,7 @@ QNetworkReply *Account::getRequest(const QString &relPath)
QNetworkReply *Account::getRequest(const QUrl &url)
{
QNetworkRequest request(url);
+ request.setSslConfiguration(this->createSslConfig());
return _am->get(request);
}
@@ -305,14 +307,61 @@ QNetworkReply *Account::davRequest(const QByteArray &verb, const QString &relPat
QNetworkReply *Account::davRequest(const QByteArray &verb, const QUrl &url, QNetworkRequest req, QIODevice *data)
{
req.setUrl(url);
+ req.setSslConfiguration(this->createSslConfig());
return _am->sendCustomRequest(req, verb, data);
}
+void Account::setCertificate(const QByteArray certficate, const QString privateKey)
+{
+ _pemCertificate=certficate;
+ _pemPrivateKey=privateKey;
+}
+
void Account::setSslConfiguration(const QSslConfiguration &config)
{
_sslConfiguration = config;
}
+QSslConfiguration Account::createSslConfig()
+{
+ // if setting the client certificate fails, you will probably get an error similar to this:
+ // "An internal error number 1060 happened. SSL handshake failed, client certificate was requested: SSL error: sslv3 alert handshake failure"
+
+ // maybe this code must not have to be reevaluated every request?
+ QSslConfiguration sslConfig;
+ QSslCertificate sslClientCertificate;
+
+ // maybe move this code from createSslConfig to the Account constructor
+ ConfigFile cfgFile;
+ if(!cfgFile.certificatePath().isEmpty() && !cfgFile.certificatePasswd().isEmpty()) {
+ resultP12ToPem certif = p12ToPem(cfgFile.certificatePath().toStdString(), cfgFile.certificatePasswd().toStdString());
+ QString s = QString::fromStdString(certif.Certificate);
+ QByteArray ba = s.toLocal8Bit();
+ this->setCertificate(ba, QString::fromStdString(certif.PrivateKey));
+ }
+ if((!_pemCertificate.isEmpty())&&(!_pemPrivateKey.isEmpty())) {
+ // Read certificates
+ QList sslCertificateList = QSslCertificate::fromData(_pemCertificate, QSsl::Pem);
+ if(sslCertificateList.length() != 0) {
+ sslClientCertificate = sslCertificateList.takeAt(0);
+ }
+ // Read key from file
+ QSslKey privateKey(_pemPrivateKey.toLocal8Bit(), QSsl::Rsa, QSsl::Pem, QSsl::PrivateKey , "");
+
+ // SSL configuration
+ sslConfig.defaultConfiguration();
+ sslConfig.setCaCertificates(QSslSocket::systemCaCertificates());
+ QList caCertifs = sslConfig.caCertificates();
+ sslConfig.setLocalCertificate(sslClientCertificate);
+ sslConfig.setPrivateKey(privateKey);
+ qDebug() << "Added SSL client certificate to the query";
+ } else {
+ qDebug() << "Failed to add the SSL client certificate to the query!";
+ }
+
+ return sslConfig;
+}
+
void Account::setApprovedCerts(const QList certs)
{
_approvedCerts = certs;
@@ -387,32 +436,34 @@ void Account::setCredentialSetting(const QString &key, const QVariant &value)
void Account::slotHandleErrors(QNetworkReply *reply , QList errors)
{
NetworkJobTimeoutPauser pauser(reply);
- qDebug() << "SSL-Errors happened for url " << reply->url().toString();
+ QString out;
+ QDebug(&out) << "SSL-Errors happened for url " << reply->url().toString();
foreach(const QSslError &error, errors) {
- qDebug() << "\tError in " << error.certificate() << ":"
- << error.errorString() << "("<< error.error()<< ")";
+ QDebug(&out) << "\tError in " << error.certificate() << ":"
+ << error.errorString() << "("<< error.error() << ")" << "\n";
}
if( _treatSslErrorsAsFailure ) {
// User decided once not to trust. Honor this decision.
- qDebug() << "Certs not trusted by user decision, returning.";
+ qDebug() << out << "Certs not trusted by user decision, returning.";
return;
}
QList approvedCerts;
if (_sslErrorHandler.isNull() ) {
- qDebug() << Q_FUNC_INFO << "called without valid SSL error handler for account" << url();
+ qDebug() << out << Q_FUNC_INFO << "called without valid SSL error handler for account" << url();
+ return;
+ }
+
+ if (_sslErrorHandler->handleErrors(errors, &approvedCerts, sharedFromThis())) {
+ QSslSocket::addDefaultCaCertificates(approvedCerts);
+ addApprovedCerts(approvedCerts);
+ // all ssl certs are known and accepted. We can ignore the problems right away.
+// qDebug() << out << "Certs are known and trusted! This is not an actual error.";
+ reply->ignoreSslErrors();
} else {
- if (_sslErrorHandler->handleErrors(errors, &approvedCerts, sharedFromThis())) {
- QSslSocket::addDefaultCaCertificates(approvedCerts);
- addApprovedCerts(approvedCerts);
- // all ssl certs are known and accepted. We can ignore the problems right away.
- qDebug() << "Certs are already known and trusted, Errors are not valid.";
- reply->ignoreSslErrors();
- } else {
- _treatSslErrorsAsFailure = true;
- return;
- }
+ _treatSslErrorsAsFailure = true;
+ return;
}
}
diff --git a/src/libsync/account.h b/src/libsync/account.h
index 8b5b1dfce6..3d677469a0 100644
--- a/src/libsync/account.h
+++ b/src/libsync/account.h
@@ -19,6 +19,7 @@
#include
#include
#include
+#include
#include
#include
#include
@@ -123,6 +124,7 @@ public:
QNetworkReply* davRequest(const QByteArray &verb, const QUrl &url, QNetworkRequest req, QIODevice *data = 0);
/** The ssl configuration during the first connection */
+ QSslConfiguration createSslConfig();
QSslConfiguration sslConfiguration() const { return _sslConfiguration; }
void setSslConfiguration(const QSslConfiguration &config);
/** The certificates of the account */
@@ -144,6 +146,8 @@ public:
QVariant credentialSetting(const QString& key) const;
void setCredentialSetting(const QString& key, const QVariant &value);
+ void setCertificate(const QByteArray certficate = QByteArray(), const QString privateKey = QString());
+
void clearCookieJar();
QNetworkAccessManager* networkAccessManager();
@@ -169,10 +173,14 @@ private:
QList _approvedCerts;
QSslConfiguration _sslConfiguration;
QScopedPointer _sslErrorHandler;
+ QuotaInfo *_quotaInfo;
QNetworkAccessManager *_am;
AbstractCredentials* _credentials;
bool _treatSslErrorsAsFailure;
+ int _state;
static QString _configFileName;
+ QByteArray _pemCertificate;
+ QString _pemPrivateKey;
QString _davPath; // default "remote.php/webdav/";
bool _wasMigrated;
};
diff --git a/src/libsync/configfile.cpp b/src/libsync/configfile.cpp
index 01dc70b2fb..ceadbda67e 100644
--- a/src/libsync/configfile.cpp
+++ b/src/libsync/configfile.cpp
@@ -64,6 +64,9 @@ static const char downloadLimitC[] = "BWLimit/downloadLimit";
static const char maxLogLinesC[] = "Logging/maxLogLines";
+const char certPath[] = "http_certificatePath";
+const char certDate[] = "http_certificateDate";
+const char certPasswd[] = "http_certificatePasswd";
QString ConfigFile::_confDir = QString::null;
bool ConfigFile::_askedUser = false;
@@ -213,6 +216,7 @@ QString ConfigFile::excludeFile(Scope scope) const
// prefer sync-exclude.lst, but if it does not exist, check for
// exclude.lst for compatibility reasons in the user writeable
// directories.
+ QFileInfo fi;
if (scope != SystemScope) {
QFileInfo fi;
@@ -255,6 +259,7 @@ QString ConfigFile::excludeFileFromSystem()
fi.setFile( QCoreApplication::applicationDirPath(),
QLatin1String("../Resources/") + exclFile );
#endif
+
return fi.absoluteFilePath();
}
@@ -567,4 +572,40 @@ void ConfigFile::setCrashReporter(bool enabled)
settings.setValue(QLatin1String(crashReporterC), enabled);
}
+QString ConfigFile::certificatePath() const
+{
+ return retrieveData(QString(), QLatin1String(certPath)).toString();
+}
+
+void ConfigFile::setCertificatePath(const QString& cPath)
+{
+ QSettings settings(configFile(), QSettings::IniFormat);
+ settings.setValue( QLatin1String(certPath), cPath);
+ settings.sync();
+}
+
+QString ConfigFile::certificateDate() const
+{
+ return retrieveData(QString(), QLatin1String(certDate)).toString();
+}
+
+void ConfigFile::setCertificateDate(const QString& cDate)
+{
+ QSettings settings(configFile(), QSettings::IniFormat);
+ settings.setValue( QLatin1String(certDate), cDate);
+ settings.sync();
+}
+
+QString ConfigFile::certificatePasswd() const
+{
+ return retrieveData(QString(), QLatin1String(certPasswd)).toString();
+}
+
+void ConfigFile::setCertificatePasswd(const QString& cPasswd)
+{
+ QSettings settings(configFile(), QSettings::IniFormat);
+ settings.setValue( QLatin1String(certPasswd), cPasswd);
+ settings.sync();
+}
+
}
diff --git a/src/libsync/configfile.h b/src/libsync/configfile.h
index 64d98df462..4635a0561b 100644
--- a/src/libsync/configfile.h
+++ b/src/libsync/configfile.h
@@ -12,8 +12,8 @@
* for more details.
*/
-#ifndef MIRALLCONFIGFILE_H
-#define MIRALLCONFIGFILE_H
+#ifndef CONFIGFILE_H
+#define CONFIGFILE_H
#include "owncloudlib.h"
#include
@@ -116,6 +116,13 @@ public:
void saveGeometryHeader(QHeaderView *header);
void restoreGeometryHeader(QHeaderView *header);
+ QString certificatePath() const;
+ void setCertificatePath(const QString& cPath);
+ QString certificateDate() const;
+ void setCertificateDate(const QString& cDate);
+ QString certificatePasswd() const;
+ void setCertificatePasswd(const QString& cPasswd);
+
protected:
QVariant getPolicySetting(const QString& policy, const QVariant& defaultValue = QVariant()) const;
void storeData(const QString& group, const QString& key, const QVariant& value);
@@ -137,4 +144,4 @@ private:
};
}
-#endif // MIRALLCONFIGFILE_H
+#endif // CONFIGFILE_H
diff --git a/src/libsync/creds/http/httpconfigfile.h b/src/libsync/creds/http/httpconfigfile.h
index 6c0aabb024..3781d13315 100644
--- a/src/libsync/creds/http/httpconfigfile.h
+++ b/src/libsync/creds/http/httpconfigfile.h
@@ -30,6 +30,12 @@ public:
bool passwordExists() const;
void removePassword();
void fixupOldPassword();
+ QString certificatePath() const;
+ void setCertificatePath(const QString& cPath);
+ QString certificateDate() const;
+ void setCertificateDate(const QString& cDate);
+ QString certificatePasswd() const;
+ void setCertificatePasswd(const QString& cPasswd);
private:
void removeOldPassword();
diff --git a/src/libsync/creds/httpcredentials.cpp b/src/libsync/creds/httpcredentials.cpp
index 95be072f38..590dfa7f25 100644
--- a/src/libsync/creds/httpcredentials.cpp
+++ b/src/libsync/creds/httpcredentials.cpp
@@ -59,6 +59,9 @@ int getauth(const char *prompt,
QString qPrompt = QString::fromLatin1( prompt ).trimmed();
QString user = http_credentials->user();
QString pwd = http_credentials->password();
+ QString certificatePath = http_credentials->certificatePath();
+ QString certificateDate = http_credentials->certificateDate();
+ QString certificatePasswd = http_credentials->certificatePasswd();
if( qPrompt == QLatin1String("Enter your username:") ) {
// qDebug() << "OOO Username requested!";
@@ -79,6 +82,9 @@ int getauth(const char *prompt,
namespace
{
const char userC[] = "user";
+const char certifPathC[] = "certificatePath";
+const char certifPasswdC[] = "certificatePasswd";
+const char certifDateC[] = "certificateDate";
const char authenticationFailedC[] = "owncloud-authentication-failed";
} // ns
@@ -101,15 +107,21 @@ private:
HttpCredentials::HttpCredentials()
: _user(),
_password(),
+ _certificatePath(),
+ _certificateDate(),
+ _certificatePasswd(),
_ready(false),
_fetchJobInProgress(false),
_readPwdFromDeprecatedPlace(false)
{
}
-HttpCredentials::HttpCredentials(const QString& user, const QString& password)
+HttpCredentials::HttpCredentials(const QString& user, const QString& password, const QString& certificatePath, const QString& certificateDate, const QString& certificatePasswd)
: _user(user),
_password(password),
+ _certificatePath(certificatePath),
+ _certificateDate(certificateDate),
+ _certificatePasswd(certificatePasswd),
_ready(true),
_fetchJobInProgress(false)
{
@@ -118,6 +130,13 @@ HttpCredentials::HttpCredentials(const QString& user, const QString& password)
void HttpCredentials::syncContextPreInit (CSYNC* ctx)
{
csync_set_auth_callback (ctx, getauth);
+ // create a SSL client certificate configuration in CSYNC* ctx
+ struct csync_client_certs_s clientCerts;
+ clientCerts.certificatePath = strdup(_certificatePath.toStdString().c_str());
+ clientCerts.certificatePasswd = strdup(_certificatePasswd.toStdString().c_str());
+ csync_set_module_property(ctx, "SSLClientCerts", &clientCerts);
+ free(clientCerts.certificatePath);
+ free(clientCerts.certificatePasswd);
}
void HttpCredentials::syncContextPreStart (CSYNC* ctx)
@@ -167,6 +186,21 @@ QString HttpCredentials::password() const
return _password;
}
+QString HttpCredentials::certificatePath() const
+{
+ return _certificatePath;
+}
+
+QString HttpCredentials::certificateDate() const
+{
+ return _certificateDate;
+}
+
+QString HttpCredentials::certificatePasswd() const
+{
+ return _certificatePasswd;
+}
+
QNetworkAccessManager* HttpCredentials::getQNAM() const
{
AccessManager* qnam = new HttpCredentialsAccessManager(this);
@@ -196,6 +230,9 @@ void HttpCredentials::fetch()
// User must be fetched from config file
fetchUser();
+ _certificatePath = _account->credentialSetting(QLatin1String(certifPathC)).toString();
+ _certificatePasswd = _account->credentialSetting(QLatin1String(certifPasswdC)).toString();
+ _certificateDate = _account->credentialSetting(QLatin1String(certifDateC)).toString();
QSettings *settings = _account->settingsWithGroup(Theme::instance()->appName());
const QString kck = keychainKey(_account->url().toString(), _user );
@@ -322,6 +359,9 @@ void HttpCredentials::persist()
return;
}
_account->setCredentialSetting(QLatin1String(userC), _user);
+ _account->setCredentialSetting(QLatin1String(certifPathC), _certificatePath);
+ _account->setCredentialSetting(QLatin1String(certifPasswdC), _certificatePasswd);
+ _account->setCredentialSetting(QLatin1String(certifDateC), _certificateDate);
WritePasswordJob *job = new WritePasswordJob(Theme::instance()->appName());
QSettings *settings = _account->settingsWithGroup(Theme::instance()->appName());
settings->setParent(job); // make the job parent to make setting deleted properly
diff --git a/src/libsync/creds/httpcredentials.h b/src/libsync/creds/httpcredentials.h
index 1a2aa78b76..f476e78b67 100644
--- a/src/libsync/creds/httpcredentials.h
+++ b/src/libsync/creds/httpcredentials.h
@@ -36,7 +36,7 @@ class OWNCLOUDSYNC_EXPORT HttpCredentials : public AbstractCredentials
public:
explicit HttpCredentials();
- HttpCredentials(const QString& user, const QString& password);
+ HttpCredentials(const QString& user, const QString& password, const QString& certificatePath, const QString& certificateDate, const QString& certificatePasswd);
void syncContextPreInit(CSYNC* ctx) Q_DECL_OVERRIDE;
void syncContextPreStart(CSYNC* ctx) Q_DECL_OVERRIDE;
@@ -53,6 +53,9 @@ public:
void invalidateToken() Q_DECL_OVERRIDE;
QString fetchUser();
virtual bool sslIsTrusted() { return false; }
+ QString certificatePath() const;
+ QString certificateDate() const;
+ QString certificatePasswd() const;
private Q_SLOTS:
void slotAuthentication(QNetworkReply*, QAuthenticator*);
@@ -64,6 +67,9 @@ protected:
QString _password;
private:
+ QString _certificatePath;
+ QString _certificateDate;
+ QString _certificatePasswd;
bool _ready;
bool _fetchJobInProgress; //True if the keychain job is in progress or the input dialog visible
bool _readPwdFromDeprecatedPlace;
@@ -72,7 +78,7 @@ private:
class OWNCLOUDSYNC_EXPORT HttpCredentialsGui : public HttpCredentials {
public:
explicit HttpCredentialsGui() : HttpCredentials() {}
- HttpCredentialsGui(const QString& user, const QString& password) : HttpCredentials(user, password) {}
+ HttpCredentialsGui(const QString& user, const QString& password, const QString& certificatePath, const QString& certificateDate, const QString& certificatePasswd) : HttpCredentials(user, password, certificatePath, certificateDate, certificatePasswd) {}
QString queryPassword(bool *ok) Q_DECL_OVERRIDE;
};
diff --git a/src/libsync/networkjobs.cpp b/src/libsync/networkjobs.cpp
index 3dd94ccb03..8aa3b9d1ab 100644
--- a/src/libsync/networkjobs.cpp
+++ b/src/libsync/networkjobs.cpp
@@ -154,6 +154,10 @@ void AbstractNetworkJob::slotFinished()
{
_timer.stop();
+ if( _reply->error() == QNetworkReply::SslHandshakeFailedError ) {
+ qDebug() << "SslHandshakeFailedError: " << reply()->errorString() << " : can be caused by a webserver wanting SSL client certificates";
+ }
+
if( _reply->error() != QNetworkReply::NoError ) {
qDebug() << Q_FUNC_INFO << _reply->error() << _reply->errorString();
if (_reply->error() == QNetworkReply::ProxyAuthenticationRequiredError) {