mirror of
https://github.com/lubosz/overte.git
synced 2025-08-07 19:41:20 +02:00
Initial OAuth2 login working
This commit is contained in:
parent
56ba137ee3
commit
aff3275207
1 changed files with 48 additions and 24 deletions
|
@ -29,17 +29,19 @@
|
||||||
#include "udt/PacketHeaders.h"
|
#include "udt/PacketHeaders.h"
|
||||||
#include "NetworkAccessManager.h"
|
#include "NetworkAccessManager.h"
|
||||||
|
|
||||||
const bool VERBOSE_HTTP_REQUEST_DEBUGGING = false;
|
// FIXME: Generalize to other OAuth2 sources for domain login.
|
||||||
const QString ACCOUNT_MANAGER_REQUESTED_SCOPE = "owner";
|
|
||||||
|
|
||||||
|
const bool VERBOSE_HTTP_REQUEST_DEBUGGING = false;
|
||||||
|
const QString DOMAIN_ACCOUNT_MANAGER_REQUESTED_SCOPE = "foo bar"; // ####### TODO: WordPress plugin's required scope.
|
||||||
|
// ####### TODO: Should scope be configured in domain server settings?
|
||||||
|
|
||||||
|
// ####### TODO: Add storing domain URL and check against it when retrieving values?
|
||||||
|
// ####### TODO: Add storing _authURL and check against it when retrieving values?
|
||||||
Setting::Handle<QString> domainAccessToken {"private/domainAccessToken", "" };
|
Setting::Handle<QString> domainAccessToken {"private/domainAccessToken", "" };
|
||||||
Setting::Handle<QString> domainAccessRefreshToken {"private/domainAccessToken", "" };
|
Setting::Handle<QString> domainAccessRefreshToken {"private/domainAccessToken", "" };
|
||||||
Setting::Handle<int> domainAccessTokenExpiresIn {"private/domainAccessTokenExpiresIn", -1 };
|
Setting::Handle<int> domainAccessTokenExpiresIn {"private/domainAccessTokenExpiresIn", -1 };
|
||||||
Setting::Handle<QString> domainAccessTokenType {"private/domainAccessTokenType", "" };
|
Setting::Handle<QString> domainAccessTokenType {"private/domainAccessTokenType", "" };
|
||||||
|
|
||||||
QUrl _domainAuthProviderURL;
|
|
||||||
|
|
||||||
// FIXME: If you try to authenticate this way on another domain, no one knows what will happen. Probably death.
|
|
||||||
|
|
||||||
DomainAccountManager::DomainAccountManager() {
|
DomainAccountManager::DomainAccountManager() {
|
||||||
connect(this, &DomainAccountManager::loginComplete, this, &DomainAccountManager::sendInterfaceAccessTokenToServer);
|
connect(this, &DomainAccountManager::loginComplete, this, &DomainAccountManager::sendInterfaceAccessTokenToServer);
|
||||||
|
@ -57,25 +59,29 @@ void DomainAccountManager::setAuthURL(const QUrl& authURL) {
|
||||||
|
|
||||||
void DomainAccountManager::requestAccessToken(const QString& login, const QString& password) {
|
void DomainAccountManager::requestAccessToken(const QString& login, const QString& password) {
|
||||||
|
|
||||||
QNetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance();
|
|
||||||
|
|
||||||
QNetworkRequest request;
|
QNetworkRequest request;
|
||||||
request.setAttribute(QNetworkRequest::FollowRedirectsAttribute, true);
|
|
||||||
request.setHeader(QNetworkRequest::UserAgentHeader, NetworkingConstants::VIRCADIA_USER_AGENT);
|
request.setHeader(QNetworkRequest::UserAgentHeader, NetworkingConstants::VIRCADIA_USER_AGENT);
|
||||||
|
|
||||||
_domainAuthProviderURL = _authURL;
|
|
||||||
_domainAuthProviderURL.setPath("/oauth/token");
|
|
||||||
|
|
||||||
QByteArray postData;
|
|
||||||
postData.append("grant_type=password&");
|
|
||||||
postData.append("username=" + QUrl::toPercentEncoding(login) + "&");
|
|
||||||
postData.append("password=" + QUrl::toPercentEncoding(password) + "&");
|
|
||||||
postData.append("scope=" + ACCOUNT_MANAGER_REQUESTED_SCOPE);
|
|
||||||
|
|
||||||
request.setUrl(_domainAuthProviderURL);
|
|
||||||
request.setHeader(QNetworkRequest::ContentTypeHeader, "application/x-www-form-urlencoded");
|
request.setHeader(QNetworkRequest::ContentTypeHeader, "application/x-www-form-urlencoded");
|
||||||
|
// ####### TODO: WordPress plugin's authorization requirements.
|
||||||
|
request.setRawHeader(QByteArray("Authorization"), QByteArray("Basic b2F1dGgtY2xpZW50LTE6b2F1dGgtY2xpZW50LXNlY3JldC0x"));
|
||||||
|
|
||||||
QNetworkReply* requestReply = networkAccessManager.post(request, postData);
|
QByteArray formData;
|
||||||
|
formData.append("grant_type=password&");
|
||||||
|
formData.append("username=" + QUrl::toPercentEncoding(login) + "&");
|
||||||
|
formData.append("password=" + QUrl::toPercentEncoding(password) + "&");
|
||||||
|
formData.append("scope=" + DOMAIN_ACCOUNT_MANAGER_REQUESTED_SCOPE);
|
||||||
|
// ####### TODO: Include state?
|
||||||
|
|
||||||
|
QUrl domainAuthURL = _authURL;
|
||||||
|
domainAuthURL.setPath("/token"); // ####### TODO: miniOrange-mandated URL. ####### TODO: Should this be included in the server settings value?
|
||||||
|
request.setUrl(domainAuthURL);
|
||||||
|
|
||||||
|
request.setAttribute(QNetworkRequest::FollowRedirectsAttribute, true);
|
||||||
|
|
||||||
|
QNetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance();
|
||||||
|
QNetworkReply* requestReply = networkAccessManager.post(request, formData);
|
||||||
connect(requestReply, &QNetworkReply::finished, this, &DomainAccountManager::requestAccessTokenFinished);
|
connect(requestReply, &QNetworkReply::finished, this, &DomainAccountManager::requestAccessTokenFinished);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -86,19 +92,25 @@ void DomainAccountManager::requestAccessTokenFinished() {
|
||||||
const QJsonObject& rootObject = jsonResponse.object();
|
const QJsonObject& rootObject = jsonResponse.object();
|
||||||
|
|
||||||
if (!rootObject.contains("error")) {
|
if (!rootObject.contains("error")) {
|
||||||
// construct an OAuthAccessToken from the json object
|
// ####### TODO: Process response scope?
|
||||||
|
// ####### TODO: Process response state?
|
||||||
|
|
||||||
if (!rootObject.contains("access_token") || !rootObject.contains("expires_in")
|
if (!rootObject.contains("access_token")
|
||||||
|
// ####### TODO: Does WordPRess plugin provide "expires_in"?
|
||||||
|
// If so, handle here, or is it just the domain server that needs to use it?
|
||||||
|
//|| !rootObject.contains("expires_in")
|
||||||
|| !rootObject.contains("token_type")) {
|
|| !rootObject.contains("token_type")) {
|
||||||
// TODO: error handling - malformed token response
|
|
||||||
qCDebug(networking) << "Received a response for password grant that is missing one or more expected values.";
|
qCDebug(networking) << "Received a response for password grant that is missing one or more expected values.";
|
||||||
|
emit loginFailed();
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
// clear the path from the response URL so we have the right root URL for this access token
|
// clear the path from the response URL so we have the right root URL for this access token
|
||||||
QUrl rootURL = requestReply->url();
|
QUrl rootURL = requestReply->url();
|
||||||
rootURL.setPath("");
|
rootURL.setPath("");
|
||||||
|
|
||||||
qCDebug(networking) << "Storing a domain account with access-token for" << qPrintable(rootURL.toString());
|
qCDebug(networking) << "Storing a domain account with access-token for" << qPrintable(rootURL.toString());
|
||||||
|
|
||||||
setAccessTokenFromJSON(rootObject);
|
setAccessTokenFromJSON(rootObject);
|
||||||
|
|
||||||
emit loginComplete(rootURL);
|
emit loginComplete(rootURL);
|
||||||
|
@ -114,7 +126,11 @@ void DomainAccountManager::sendInterfaceAccessTokenToServer() {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool DomainAccountManager::accessTokenIsExpired() {
|
bool DomainAccountManager::accessTokenIsExpired() {
|
||||||
|
// ####### TODO: accessTokenIsExpired()
|
||||||
|
return true;
|
||||||
|
/*
|
||||||
return domainAccessTokenExpiresIn.get() != -1 && domainAccessTokenExpiresIn.get() <= QDateTime::currentMSecsSinceEpoch();
|
return domainAccessTokenExpiresIn.get() != -1 && domainAccessTokenExpiresIn.get() <= QDateTime::currentMSecsSinceEpoch();
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -125,7 +141,7 @@ bool DomainAccountManager::hasValidAccessToken() {
|
||||||
|
|
||||||
if (VERBOSE_HTTP_REQUEST_DEBUGGING) {
|
if (VERBOSE_HTTP_REQUEST_DEBUGGING) {
|
||||||
qCDebug(networking) << "An access token is required for requests to"
|
qCDebug(networking) << "An access token is required for requests to"
|
||||||
<< qPrintable(_domainAuthProviderURL.toString());
|
<< qPrintable(_authURL.toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
|
@ -143,15 +159,23 @@ bool DomainAccountManager::hasValidAccessToken() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void DomainAccountManager::setAccessTokenFromJSON(const QJsonObject& jsonObject) {
|
void DomainAccountManager::setAccessTokenFromJSON(const QJsonObject& jsonObject) {
|
||||||
|
// ####### TODO: Enable and use these.
|
||||||
|
/*
|
||||||
domainAccessToken.set(jsonObject["access_token"].toString());
|
domainAccessToken.set(jsonObject["access_token"].toString());
|
||||||
domainAccessRefreshToken.set(jsonObject["refresh_token"].toString());
|
domainAccessRefreshToken.set(jsonObject["refresh_token"].toString());
|
||||||
domainAccessTokenExpiresIn.set(QDateTime::currentMSecsSinceEpoch() + (jsonObject["expires_in"].toDouble() * 1000));
|
domainAccessTokenExpiresIn.set(QDateTime::currentMSecsSinceEpoch() + (jsonObject["expires_in"].toDouble() * 1000));
|
||||||
domainAccessTokenType.set(jsonObject["token_type"].toString());
|
domainAccessTokenType.set(jsonObject["token_type"].toString());
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
bool DomainAccountManager::checkAndSignalForAccessToken() {
|
bool DomainAccountManager::checkAndSignalForAccessToken() {
|
||||||
bool hasToken = hasValidAccessToken();
|
bool hasToken = hasValidAccessToken();
|
||||||
|
|
||||||
|
// ####### TODO: Handle hasToken == true.
|
||||||
|
// It causes the login dialog not to display (OK) but somewhere the domain server needs to be sent it (and if domain server
|
||||||
|
// gets error when trying to use it then user should be prompted to login).
|
||||||
|
hasToken = false;
|
||||||
|
|
||||||
if (!hasToken) {
|
if (!hasToken) {
|
||||||
// Emit a signal so somebody can call back to us and request an access token given a user name and password.
|
// Emit a signal so somebody can call back to us and request an access token given a user name and password.
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue