#include "ubuntuoneauthenticator.h" #include #include #include #include #include #include #include "core/closure.h" #include "core/logging.h" #include "core/network.h" #include "core/timeconstants.h" namespace { static const char* kUbuntuOneEndpoint = "https://login.ubuntu.com/api/1.0/authentications"; static const char* kTokenNameTemplate = "Ubuntu One @ %1 [%2]"; static const char* kOAuthSSOFinishedEndpoint = "https://one.ubuntu.com/oauth/sso-finished-so-get-tokens/"; static const char* kOAuthHeaderPrefix = "OAuth realm=\"\", "; } UbuntuOneAuthenticator::UbuntuOneAuthenticator(QObject* parent) : QObject(parent), network_(new NetworkAccessManager(this)), success_(false) {} void UbuntuOneAuthenticator::StartAuthorisation(const QString& email, const QString& password) { QUrl url(kUbuntuOneEndpoint); url.addQueryItem("ws.op", "authenticate"); QString token_name = QString(kTokenNameTemplate).arg( QHostInfo::localHostName(), QCoreApplication::applicationName()); url.addQueryItem("token_name", token_name); QByteArray authentication = QString(email + ":" + password).toAscii().toBase64(); QString authorisation = QString("Basic %1").arg(QString::fromAscii(authentication)); QNetworkRequest request(url); request.setRawHeader("Authorization", authorisation.toAscii()); request.setRawHeader("Accept", "application/json"); QNetworkReply* reply = network_->get(request); NewClosure(reply, SIGNAL(finished()), this, SLOT(AuthorisationFinished(QNetworkReply*)), reply); qLog(Debug) << url; qLog(Debug) << authorisation; } void UbuntuOneAuthenticator::AuthorisationFinished(QNetworkReply* reply) { reply->deleteLater(); QByteArray data = reply->readAll(); qLog(Debug) << data; QJson::Parser parser; bool ok = false; QVariant json = parser.parse(data, &ok); if (!ok) { qLog(Error) << "Failed to authenticate to Ubuntu One:" << parser.errorString(); emit Finished(); return; } QVariantMap auth_info = json.toMap(); consumer_key_ = auth_info["consumer_key"].toString(); consumer_secret_ = auth_info["consumer_secret"].toString(); token_ = auth_info["token"].toString(); token_secret_ = auth_info["token_secret"].toString(); CopySSOTokens(); } QByteArray UbuntuOneAuthenticator::GenerateAuthorisationHeader( const QString& consumer_key, const QString& consumer_secret, const QString& token, const QString& token_secret) { typedef QPair Param; QString timestamp = QString::number(time(nullptr)); QList parameters; parameters << Param("oauth_nonce", QString::number(qrand())) << Param("oauth_timestamp", timestamp) << Param("oauth_version", "1.0") << Param("oauth_consumer_key", consumer_key) << Param("oauth_token", token) << Param("oauth_signature_method", "PLAINTEXT"); qSort(parameters.begin(), parameters.end()); QStringList encoded_params; for (const Param& p : parameters) { encoded_params << QString("%1=%2").arg(p.first, p.second); } QString signing_key = consumer_secret + "&" + token_secret; QByteArray signature = QUrl::toPercentEncoding(signing_key); // Construct authorisation header parameters << Param("oauth_signature", signature); QStringList header_params; for (const Param& p : parameters) { header_params << QString("%1=\"%2\"").arg(p.first, p.second); } QString authorisation_header = header_params.join(", "); authorisation_header.prepend(kOAuthHeaderPrefix); return authorisation_header.toAscii(); } QByteArray UbuntuOneAuthenticator::GenerateAuthorisationHeader() { return GenerateAuthorisationHeader(consumer_key_, consumer_secret_, token_, token_secret_); } void UbuntuOneAuthenticator::CopySSOTokens() { QUrl url(kOAuthSSOFinishedEndpoint); QNetworkRequest request(url); request.setRawHeader("Authorization", GenerateAuthorisationHeader()); request.setRawHeader("Accept", "application/json"); QNetworkReply* reply = network_->get(request); NewClosure(reply, SIGNAL(finished()), this, SLOT(CopySSOTokensFinished(QNetworkReply*)), reply); } void UbuntuOneAuthenticator::CopySSOTokensFinished(QNetworkReply* reply) { reply->deleteLater(); qLog(Debug) << reply->readAll(); success_ = true; emit Finished(); }