diff --git a/libnymea-app-core/awsclient.cpp b/libnymea-app-core/awsclient.cpp index 40f1ba7b..1a82e596 100644 --- a/libnymea-app-core/awsclient.cpp +++ b/libnymea-app-core/awsclient.cpp @@ -11,49 +11,42 @@ extern "C" { #include "connection/srp.h" } +static QByteArray clientId = "8rjhfdlf9jf1suok2jcrltd6v"; + AWSClient::AWSClient(QObject *parent) : QObject(parent) { m_nam = new QNetworkAccessManager(this); } -void AWSClient::login() +void AWSClient::login(const QString &username, const QString &password) { + if (m_srpUser != nullptr) { + qWarning() << "Already logged in. Cannot log in again"; + return; + } - QString pass = "H22*xgemmmmm"; -// SRPUser* srpUser = srp_user_new(SRP_SHA256, SRP_NG_2048, "michael.zanetti@guh.io", (const unsigned char*)pass.toLocal8Bit().data(), pass.length(), nullptr ,nullptr); - SRPUser* srpUser = srp_user_new(SRP_SHA256, SRP_NG_2048, "michael.zanetti@guh.io", (const unsigned char*)"H22*xgemmmmm", pass.length(), nullptr ,nullptr); + m_srpUser = srp_user_new(SRP_SHA256, SRP_NG_2048, username.toLocal8Bit(), (const unsigned char*)password.toLocal8Bit().data(), password.length(), nullptr ,nullptr); + + char *user; + unsigned char *bytes_A; + int len_A; + srp_user_start_authentication(m_srpUser, (const char**)&user, (const unsigned char**)&bytes_A, &len_A); QUrl url("https://cognito-idp.eu-west-1.amazonaws.com/"); -// QUrl url("https://iam.amazonaws.com/"); QUrlQuery query; query.addQueryItem("Action", "InitiateAuth"); query.addQueryItem("Version", "2016-04-18"); -// url.setQuery(query); + url.setQuery(query); QNetworkRequest request(url); - - request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json; charset=utf-8"); -// request.setHeader(QNetworkRequest::ContentTypeHeader, "application/x-amz-json-1.0"); -// request.setRawHeader("Action", "InitiateAuth"); + request.setHeader(QNetworkRequest::ContentTypeHeader, "application/x-amz-json-1.0"); request.setRawHeader("Host", "cognito-idp.eu-west-1.amazonaws.com"); -// request.setRawHeader("x-amz-date", QDateTime::currentDateTime().toString(Qt::ISODate).toUtf8()); - request.setRawHeader("X-Amz-Date", QDateTime::currentDateTime().toString("yyyyMMddThhmmssZ").toUtf8()); - request.setRawHeader("X-Amz-Target", "CognitoIdentityServiceProvider.InitiateAuth"); -// request.setRawHeader("UserAgent", "None of your business"); -// request.setHeader(QNetworkRequest::ContentTypeHeader, "application/x-amz-json-1.0"); - request.setRawHeader("Version", "2016-04-18"); + request.setRawHeader("X-Amz-Target", "AWSCognitoIdentityProviderService.InitiateAuth"); QVariantMap params; params.insert("AuthFlow", "USER_SRP_AUTH"); - params.insert("ClientId", "8rjhfdlf9jf1suok2jcrltd6v"); -// params.insert("Action", "InitiateAuth"); -// params.insert("Version", "2016-04-18"); - - char *username; - unsigned char *bytes_A; - int len_A; - srp_user_start_authentication(srpUser, (const char**)&username, (const unsigned char**)&bytes_A, &len_A); + params.insert("ClientId", clientId); QVariantMap authParams; authParams.insert("USERNAME", username); @@ -62,22 +55,86 @@ void AWSClient::login() params.insert("AuthParameters", authParams); QJsonDocument jsonDoc = QJsonDocument::fromVariant(params); + QByteArray payload = jsonDoc.toJson(QJsonDocument::Compact); + qDebug() << "Posting:\nURL:" << request.url().toString(); qDebug() << "HEADERS:"; foreach (const QByteArray &headerName, request.rawHeaderList()) { qDebug() << headerName << ":" << request.rawHeader(headerName); } - QByteArray payload = jsonDoc.toJson(QJsonDocument::Compact); qDebug().noquote() << "Payload:" << payload; + QNetworkReply *reply = m_nam->post(request, payload); -// QNetworkReply *reply = m_nam->post(request, "{}"); - connect(reply, &QNetworkReply::finished, this, &AWSClient::loginReply); + connect(reply, &QNetworkReply::finished, this, &AWSClient::initiateAuthReply); } -void AWSClient::loginReply() +void AWSClient::initiateAuthReply() { QNetworkReply* reply = static_cast(sender()); - qDebug() << "login reply" << reply->error() << reply->errorString() << reply->readAll(); + reply->deleteLater(); + QByteArray data = reply->readAll(); + qDebug() << "InitiateAuth reply" << reply->error() << reply->errorString() << qUtf8Printable(data); + + QJsonParseError error; + QJsonDocument jsonDoc = QJsonDocument::fromJson(data, &error); + if (error.error != QJsonParseError::NoError) { + qWarning() << "Failed to parse AWS login response" << error.errorString(); + return; + } + QVariantMap srpChallenge = jsonDoc.toVariant().toMap(); + QByteArray challengeName = srpChallenge.value("ChallengeName").toByteArray(); + QVariantMap challengeParams = srpChallenge.value("ChallengeParameters").toMap(); + QByteArray secretBlock = challengeParams.value("SECRET_BLOCK").toByteArray(); + QByteArray srpB = challengeParams.value("SRP_B").toByteArray(); + QByteArray username = challengeParams.value("USERNAME").toByteArray(); + char *bytes_M; + int len_M; + srp_user_process_challenge(m_srpUser, (const unsigned char*)secretBlock.data(), secretBlock.length(), (const unsigned char*)srpB.data(), srpB.length(), (const unsigned char**)&bytes_M, &len_M); + + QUrl url("https://cognito-idp.eu-west-1.amazonaws.com/"); + + QUrlQuery query; + query.addQueryItem("Action", "RespondToAuthChallenge"); + query.addQueryItem("Version", "2016-04-18"); + url.setQuery(query); + + QNetworkRequest request(url); + request.setHeader(QNetworkRequest::ContentTypeHeader, "application/x-amz-json-1.0"); + request.setRawHeader("Host", "cognito-idp.eu-west-1.amazonaws.com"); + request.setRawHeader("X-Amz-Target", "AWSCognitoIdentityProviderService.RespondToAuthChallenge"); + + QVariantMap params; + params.insert("ChallengeName", challengeName.data()); + + QVariantMap challengeResponses; + challengeResponses.insert("PASSWORD_CLAIM_SIGNATURE", srpB.toHex().data()); + challengeResponses.insert("PASSWORD_CLAIM_SECRET_BLOCK", secretBlock.data()); + challengeResponses.insert("USERNAME", username); + challengeResponses.insert("TIMESTAMP", QLocale("en").toString(QDateTime::currentDateTime().toUTC(), "ddd MMM d HH:mm:ss UTC yyyy")); + params.insert("ChallengeResponses", challengeResponses); + + params.insert("ClientId", clientId); + + jsonDoc = QJsonDocument::fromVariant(params); + QByteArray payload = jsonDoc.toJson(QJsonDocument::Compact); + + qDebug() << "Posting:\nURL:" << request.url().toString(); + qDebug() << "HEADERS:"; + foreach (const QByteArray &headerName, request.rawHeaderList()) { + qDebug() << headerName << ":" << request.rawHeader(headerName); + } + qDebug().noquote() << "Payload:" << payload; + + reply = m_nam->post(request, payload); + connect(reply, &QNetworkReply::finished, this, &AWSClient::respondToAuthChallengeReply); +} + +void AWSClient::respondToAuthChallengeReply() +{ + QNetworkReply* reply = static_cast(sender()); + reply->deleteLater(); + QByteArray data = reply->readAll(); + qDebug() << "RespondToAuthChallenge reply" << reply->error() << reply->errorString() << qUtf8Printable(data); } void AWSClient::sign(QNetworkRequest &request) diff --git a/libnymea-app-core/awsclient.h b/libnymea-app-core/awsclient.h index 862d2c3a..19ca94cd 100644 --- a/libnymea-app-core/awsclient.h +++ b/libnymea-app-core/awsclient.h @@ -5,6 +5,7 @@ #include class QNetworkAccessManager; +struct SRPUser; class AWSClient : public QObject { @@ -12,13 +13,15 @@ class AWSClient : public QObject public: explicit AWSClient(QObject *parent = nullptr); - Q_INVOKABLE void login(); + Q_INVOKABLE void login(const QString &username, const QString &password); private slots: - void loginReply(); + void initiateAuthReply(); + void respondToAuthChallengeReply(); private: QNetworkAccessManager *m_nam = nullptr; + SRPUser *m_srpUser = nullptr; void sign(QNetworkRequest &request); }; diff --git a/nymea-app/ui/connection/ConnectPage.qml b/nymea-app/ui/connection/ConnectPage.qml index dee8457c..dc401262 100644 --- a/nymea-app/ui/connection/ConnectPage.qml +++ b/nymea-app/ui/connection/ConnectPage.qml @@ -106,7 +106,7 @@ Page { Engine.connection.connect("nymea://nymea.nymea.io:2222") break; case 4: - Engine.awsClient.login(); + Engine.awsClient.login("michael.zanetti@guh.io", "H22*xgemmmmm"); } } }