Welcome!

Welcome to the official BlackBerry Support Community Forums.

This is your resource to discuss support topics with your peers, and learn from each other.

inside custom component

Native Development

Reply
Developer
jbadwal
Posts: 52
Registered: ‎04-22-2012
My Device: Z10
My Carrier: Mobilicity
Accepted Solution

SecureDataSource

So I guess the DataSource object only supports HTTP and not HTTPS ?  This seems rather incomplete to me. Not sure why BB would choose to not support HTTPS.

 

In any case.. has anyone extended the provided DataSource object to create a custom 'SecureDataSource' object or sorts. AFAIK this is the only way to maintain DataSource abstraction and to have the ability to access secure servers ?

 

any help is appreciated.  laucned an app.. cant add https servers.. awesome.

Please use plain text.
BlackBerry Development Advisor (Retired)
mwoolley
Posts: 571
Registered: ‎06-25-2010
My Device: Z10
My Carrier: Vodafone

Re: SecureDataSource

You're right that unfortunately https is not supported by DataSource. Could you post a request for this feature in the developer issue tracker please and include a good description of your use case?

 

http://supportforums.blackberry.com/t5/Java-Development/Developer-Issue-Tracker/td-p/271768

 

Thank you

--------------------------------------------------------------------------------------------
Feel free to press the like button on the right side if you liked my attempts to help :-)
And please mark posts as solved if you think I found the solution or set you on its path. Thanks!
Follow me on Twitter: @mdwrim
Please use plain text.
Developer
jbadwal
Posts: 52
Registered: ‎04-22-2012
My Device: Z10
My Carrier: Mobilicity

Re: SecureDataSource

Please use plain text.
BlackBerry Development Advisor (Retired)
mwoolley
Posts: 571
Registered: ‎06-25-2010
My Device: Z10
My Carrier: Vodafone

Re: SecureDataSource

Thank you :-)

--------------------------------------------------------------------------------------------
Feel free to press the like button on the right side if you liked my attempts to help :-)
And please mark posts as solved if you think I found the solution or set you on its path. Thanks!
Follow me on Twitter: @mdwrim
Please use plain text.
Developer
jbadwal
Posts: 52
Registered: ‎04-22-2012
My Device: Z10
My Carrier: Mobilicity

Re: SecureDataSource

I'm currently attempting to create my own extented DataSource class to handle https connections.

 

im having an issue.. this doesnt work

 

#include "SecureDataSource.h"
#include <bb/data/XmlDataAccess>
#include <bb/data/JsonDataAccess>

namespace bb {
namespace indinuity {

QNetworkAccessManager * SecureDataSource::mNetManager = new QNetworkAccessManager();

SecureDataSource::SecureDataSource()
{
	this->isHttpsSource = false;
}

SecureDataSource::~SecureDataSource()
{

}

void SecureDataSource::load()
{
	if (!this->isHttpsSource) {
		DataSource::load();
		return;
	}

	// Create request
	QNetworkRequest request;
	request.setAttribute(QNetworkRequest::CacheLoadControlAttribute, QNetworkRequest::AlwaysNetwork);
	request.setUrl(this->source());

	// Create reply
	QNetworkReply * reply = mNetManager->get(request);

	bool ok = QObject::connect(reply,SIGNAL(sslErrors(const QList<QSslError> &)), this, SLOT(slotSslErrors(const QList<QSslError> &)));
	Q_ASSERT(ok);
	Q_UNUSED(ok);

	QObject::connect(reply,SIGNAL(finished()), this, SLOT(sourceLoaded()));
	QObject::connect(reply,SIGNAL(downloadProgress(qint64, qint64)), this, SLOT(dowloadProgressed(qint64,qint64)));
}

void SecureDataSource::setSource(const QUrl &source)
{
	// if its not https just pass it off to the parent.
	if (source.scheme() != "https") {
		DataSource::setSource(source);
		return;
	}
	this->isHttpsSource = true;
	DataSource::setSource(source);
}

double SecureDataSource::loading() const
{
	return mLoading;
}

void SecureDataSource::sourceLoaded()
{
	// Get reply
	QNetworkReply * reply = qobject_cast<QNetworkReply*>(sender());
	QObject::disconnect(reply,SIGNAL(finished()), this, SLOT(sourceLoaded()));
	QObject::disconnect(reply,SIGNAL(downloadProgress(qint64, qint64)), this, SLOT(dowloadProgressed(qint64,qint64)));

	// take the source data and convert it to a qvariant and emit a dataLoaded signal
	QVariantMap responseVar;
    QString response;
    bool success = false;
    if (reply)
    {
        if (reply->error() == QNetworkReply::NoError)
        {
            int available = reply->bytesAvailable();
            if (available > 0)
            {
                int bufSize = sizeof(char) * available + sizeof(char);
                QByteArray buffer(bufSize, 0);
                int read = reply->read(buffer.data(), available);
                response = QString(buffer);
                success = true;
            }
        }
        else
        {
        	response =  QString("Error: ") + reply->errorString() + QString(" status:") + reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toString();
        	qDebug() << response;
        	emit error(bb::data&colon;:DataAccessErrorType::ConnectionFailure, response);
        }
        reply->deleteLater();
    }

    if (!success) {
    	return;
    }

    if (response.trimmed().isEmpty())
    {
    	response =  QString("Error: Response has no data.");
    	qDebug() << response;
    	emit error(bb::data&colon;:DataAccessErrorType::OperationFailure, response);
    	return;
    }

    // now we convert the response to the appropriate data type
    QVariant data;
    bb::data&colon;:XmlDataAccess xda;
    bb::data&colon;:JsonDataAccess jda;

    switch (this->type()) {
    case bb::data&colon;:DataSourceType::Xml:
    	data = xda.loadFromBuffer(response);
    	if (!data.isValid()) {
        	response = QString("Error: Could not convert to XML.");
        	qDebug() << response;
        	emit error(bb::data&colon;:DataAccessErrorType::OperationFailure, response);
        	return;
    	}
    	break;
    case bb::data&colon;:DataSourceType::Json:
    	data = jda.load("contacts.json");
    	if (!data.isValid()) {
    		response = QString("Error: Could not convert to JSON.");
			qDebug() << response;
			emit error(bb::data&colon;:DataAccessErrorType::OperationFailure, response);
			return;
    	}
    	break;
    default:
    	response = QString("Error: Unknown data type.");
    	qDebug() << response;
    	emit error(bb::data&colon;:DataAccessErrorType::OperationFailure, response);
    	return;
    	break;
    }

    emit dataLoaded(data);
}

void SecureDataSource::slotSslErrors(const QList<QSslError> &errors)
{
	qDebug() << QString("[SONAR] slot ssl errors");

	QNetworkReply * reply = qobject_cast<QNetworkReply*>(sender());
	QObject::disconnect(reply,SIGNAL(sslErrors(const QList<QSslError> &)), this, SLOT(slotSslErrors(const QList<QSslError> &)));

	reply->ignoreSslErrors(errors);
}

void SecureDataSource::dowloadProgressed(qint64 bytes,qint64 total)
{
	mLoading =  double(bytes) / double(total);
	emit loadingChanged();
}

} /* namespace indinuity */
} /* namespace bb */

 

#ifndef SECUREDATASOURCE_H_
#define SECUREDATASOURCE_H_

#include <qmetatype.h>
#include <bb/data/DataSource>

using namespace bb::data;
namespace bb {
namespace indinuity {


class SecureDataSource: public bb::data&colon;:DataSource {
	Q_OBJECT
	Q_PROPERTY (QUrl source READ source WRITE setSource NOTIFY sourceChanged)
	Q_PROPERTY (float loading READ loading NOTIFY loadingChanged)

public:
	SecureDataSource();
	virtual ~SecureDataSource();

	double loading() const;

public Q_SLOTS:
	void setSource(const QUrl &source);
	void load();
	void slotSslErrors(const QList<QSslError> &errors);

private Q_SLOTS:
	void sourceLoaded();
	void dowloadProgressed(qint64,qint64);

signals:
	void sourceChanged(QUrl source);
	void loadingChanged();

private:
	static QNetworkAccessManager * mNetManager;
	float mLoading;
bool isHttpsSource; }; } /* namespace indinuity */ } /* namespace bb */ #endif /* SECUREDATASOURCE_H_ */

 

The issue it seems is though the signal for sslErrors is not being emitted.. as the slot is not being called. I have debug lines that output as soon as the slot is called but they never get logged.

 

Im also seeing these warnings

 

    - SecureDataSource::smileysurprised:nSslErrors(QNetworkReply *, const QList<QSslError> &) has not been tagged as a Qt slot; make sure all
     parameter types are fully qualified
    - QNetworkAccessManager::sslErrors(QNetworkReply *, const QList<QSslError> &) has not been tagged as a Qt signal; make sure all
     parameter types are fully qualified

 

on both the connects and disconnects to the sslErrors signal.

 

 

Please use plain text.
Developer
jbadwal
Posts: 52
Registered: ‎04-22-2012
My Device: Z10
My Carrier: Mobilicity

Re: SecureDataSource

Im still not getting anywhere with this..

 

I did add the openssl library via Configure->Add Library-> Standard BB....

 

I also added the following lines to my .pro file

 

LIBS += -lssl
LIBS += -lcrypto

 

but that signal still doesnt seem to fire and the slot is never called. Someone must know whats missing..

 

Please use plain text.
Developer
jbadwal
Posts: 52
Registered: ‎04-22-2012
My Device: Z10
My Carrier: Mobilicity

Re: SecureDataSource

Im still trying to get this working..

 

I ended up creating a QNetworkAccessManager wrapper since none of the sslError signals will fire for me on a self-signed certificate. And yup this is probably a self-signed certificate problem. Question.. do I need to download the certificate from the server first ?

 

QNetworkReply* SslNetworkAccessManager::createRequest(Operation op,
		const QNetworkRequest& req, QIODevice* outgoingData) {

	QSslConfiguration config = req.sslConfiguration();
	config.setPeerVerifyMode(QSslSocket::VerifyNone);
	config.setProtocol(QSsl::TlsV1);
	QNetworkRequest request(req);
	request.setSslConfiguration(config);

	QNetworkReply* reply = QNetworkAccessManager::createRequest(op, request, outgoingData);

	return reply;
}

 

Thats the bulk of the wrapper.. I also connected a slot to the error signal of the reply..

 

QObject::connect(reply, SIGNAL(error(QNetworkReply::NetworkError)), this, SLOT(handleSslErrors(QNetworkReply::NetworkError)));

 this fires every time.. however..

 

void SecureDataSource::handleSslErrors(QNetworkReply::NetworkError code)
{
	QNetworkReply * reply = qobject_cast<QNetworkReply*>(sender());
	QObject::connect(reply, SIGNAL(error(QNetworkReply::NetworkError)), this, SLOT(handleSslErrors(QNetworkReply::NetworkError)));

	reply->ignoreSslErrors();
}

 Attempting to ignore ssl errors does absolutely nothing!  this is such a pissoff of astronomical proportions lol.. 3 days and no head way.. and no response from anyone else dealing with something similar ?  find it hard to believe no one has had to deal with self-signed certs.

 

 

Please use plain text.
Developer
Zmey
Posts: 1,510
Registered: ‎12-18-2012
My Device: PlayBook, Z10, DAC

Re: SecureDataSource

Hi,

 

This is a wrong signal to connect to:

SIGNAL(error(QNetworkReply::NetworkError))

 

Your original code looks correct, but the errors you've posted aren't from that code:

 

In the original code QNetworkReply's signal is used:

SIGNAL(sslErrors(const QList<QSslError> &))

But the error message mentions another signal:

QNetworkAccessManager::sslErrors(QNetworkReply *, const QList<QSslError> &) 

I suggest rolling back to original code and ensuring that you're connecting to QNetworkReply, not QNetworkAccessManager and verifying signal and slot signatures (the warnings won't appear in logs if they're correct).

 

Btw, disconnecting the signals is not neccessary, they're disconnected automatically when the object is destroyed.

 


Andrey Fidrya, @zmeyc on twitter
Please use plain text.
Developer
jbadwal
Posts: 52
Registered: ‎04-22-2012
My Device: Z10
My Carrier: Mobilicity

Re: SecureDataSource

Ive continuously been changing things.. and believe it or not.. I just fixed this on my side.

 

In fact I didnt need to use the signal at all. It is better to obviously to handle those issues. I was however able to get away with not needing it.

 

In the end I just needed this.

 

	QSslConfiguration config = request.sslConfiguration();
	config.setPeerVerifyMode(QSslSocket::VerifyNone);
	// config.setProtocol(QSsl::TlsV1);
	config.setProtocol(QSsl::SslV3);
	request.setSslConfiguration(config);

 

Before the request is passed to the QNetworkAccessManager . I set peer verification to none and protocol to SslV3 . This solved my self-signed problem. I loaded up the url in the blackberry browser and noticed that the certificate was using SslV3 .. not TlsV1 .. that was my issue.

 

Going back to the signal though.. all my google searches yielded nearly the same result.. that the sslErrors signal may or may not fire. The errors signal fires always.. but even then the ignoreSslErrors() method did nothing. Im guessing ultimately, because of the protocol, the handshake could not be completed even when ignoring.. just failed.

 

 

Please use plain text.
Contributor
casantos
Posts: 33
Registered: ‎01-13-2013
My Device: BlackBerry Z10, Q10
My Carrier: Claro (Brazil)

Re: SecureDataSource

It would be good if SecureDataSource could handle authorization too. I attempted to use it to update a ListView from a JSON received from a site which requires username/password authentication.

 

Please use plain text.