diff options
Diffstat (limited to 'libraries/katabasis/include')
-rw-r--r-- | libraries/katabasis/include/katabasis/Bits.h | 6 | ||||
-rw-r--r-- | libraries/katabasis/include/katabasis/DeviceFlow.h | 150 | ||||
-rw-r--r-- | libraries/katabasis/include/katabasis/OAuth2.h | 233 | ||||
-rw-r--r-- | libraries/katabasis/include/katabasis/Reply.h | 7 | ||||
-rw-r--r-- | libraries/katabasis/include/katabasis/ReplyServer.h | 53 |
5 files changed, 160 insertions, 289 deletions
diff --git a/libraries/katabasis/include/katabasis/Bits.h b/libraries/katabasis/include/katabasis/Bits.h index 3fd2f530..f11f25d2 100644 --- a/libraries/katabasis/include/katabasis/Bits.h +++ b/libraries/katabasis/include/katabasis/Bits.h @@ -10,7 +10,11 @@ enum class Activity { Idle, LoggingIn, LoggingOut, - Refreshing + Refreshing, + FailedSoft, //!< soft failure. this generally means the user auth details haven't been invalidated + FailedHard, //!< hard failure. auth is invalid + FailedGone, //!< hard failure. auth is invalid, and the account no longer exists + Succeeded }; enum class Validity { diff --git a/libraries/katabasis/include/katabasis/DeviceFlow.h b/libraries/katabasis/include/katabasis/DeviceFlow.h new file mode 100644 index 00000000..b68c92e0 --- /dev/null +++ b/libraries/katabasis/include/katabasis/DeviceFlow.h @@ -0,0 +1,150 @@ +#pragma once + +#include <QNetworkAccessManager> +#include <QNetworkRequest> +#include <QNetworkReply> +#include <QPair> + +#include "Reply.h" +#include "RequestParameter.h" +#include "Bits.h" + +namespace Katabasis { + +class ReplyServer; +class PollServer; + +/// Simple OAuth2 Device Flow authenticator. +class DeviceFlow: public QObject +{ + Q_OBJECT +public: + Q_ENUMS(GrantFlow) + +public: + + struct Options { + QString userAgent = QStringLiteral("Katabasis/1.0"); + QString responseType = QStringLiteral("code"); + QString scope; + QString clientIdentifier; + QString clientSecret; + QUrl authorizationUrl; + QUrl accessTokenUrl; + }; + +public: + /// Are we authenticated? + bool linked(); + + /// Authentication token. + QString token(); + + /// Provider-specific extra tokens, available after a successful authentication + QVariantMap extraTokens(); + +public: + // TODO: put in `Options` + /// User-defined extra parameters to append to request URL + QVariantMap extraRequestParams(); + void setExtraRequestParams(const QVariantMap &value); + + // TODO: split up the class into multiple, each implementing one OAuth2 flow + /// Grant type (if non-standard) + QString grantType(); + void setGrantType(const QString &value); + +public: + /// Constructor. + /// @param parent Parent object. + explicit DeviceFlow(Options & opts, Token & token, QObject *parent = 0, QNetworkAccessManager *manager = 0); + + /// Get refresh token. + QString refreshToken(); + + /// Get token expiration time + QDateTime expires(); + +public slots: + /// Authenticate. + void login(); + + /// De-authenticate. + void logout(); + + /// Refresh token. + bool refresh(); + + /// Handle situation where reply server has opted to close its connection + void serverHasClosed(bool paramsfound = false); + +signals: + /// Emitted when client needs to open a web browser window, with the given URL. + void openBrowser(const QUrl &url); + + /// Emitted when client can close the browser window. + void closeBrowser(); + + /// Emitted when client needs to show a verification uri and user code + void showVerificationUriAndCode(const QUrl &uri, const QString &code, int expiresIn); + + /// Emitted when the internal state changes + void activityChanged(Activity activity); + +public slots: + /// Handle verification response. + void onVerificationReceived(QMap<QString, QString>); + +protected slots: + /// Handle completion of a Device Authorization Request + void onDeviceAuthReplyFinished(); + + /// Handle completion of a refresh request. + void onRefreshFinished(); + + /// Handle failure of a refresh request. + void onRefreshError(QNetworkReply::NetworkError error, QNetworkReply *reply); + +protected: + /// Set refresh token. + void setRefreshToken(const QString &v); + + /// Set token expiration time. + void setExpires(QDateTime v); + + /// Start polling authorization server + void startPollServer(const QVariantMap ¶ms, int expiresIn); + + /// Set authentication token. + void setToken(const QString &v); + + /// Set the linked state + void setLinked(bool v); + + /// Set extra tokens found in OAuth response + void setExtraTokens(QVariantMap extraTokens); + + /// Set local poll server + void setPollServer(PollServer *server); + + PollServer * pollServer() const; + + void updateActivity(Activity activity); + +protected: + Options options_; + + QVariantMap extraReqParams_; + QNetworkAccessManager *manager_ = nullptr; + ReplyList timedReplies_; + QString grantType_; + +protected: + Token &token_; + +private: + PollServer *pollServer_ = nullptr; + Activity activity_ = Activity::Idle; +}; + +} diff --git a/libraries/katabasis/include/katabasis/OAuth2.h b/libraries/katabasis/include/katabasis/OAuth2.h deleted file mode 100644 index 9dbe5c71..00000000 --- a/libraries/katabasis/include/katabasis/OAuth2.h +++ /dev/null @@ -1,233 +0,0 @@ -#pragma once - -#include <QNetworkAccessManager> -#include <QNetworkRequest> -#include <QNetworkReply> -#include <QPair> - -#include "Reply.h" -#include "RequestParameter.h" -#include "Bits.h" - -namespace Katabasis { - -class ReplyServer; -class PollServer; - - -/* - * FIXME: this is not as simple as it should be. it squishes 4 different grant flows into one big ball of mud - * This serves no practical purpose and simply makes the code less readable / maintainable. - * - * Therefore: Split this into the 4 different OAuth2 flows that people can use as authentication steps. Write tests/examples for all of them. - */ - -/// Simple OAuth2 authenticator. -class OAuth2: public QObject -{ - Q_OBJECT -public: - Q_ENUMS(GrantFlow) - -public: - - struct Options { - QString userAgent = QStringLiteral("Katabasis/1.0"); - QString redirectionUrl = QStringLiteral("http://localhost:%1"); - QString responseType = QStringLiteral("code"); - QString scope; - QString clientIdentifier; - QString clientSecret; - QUrl authorizationUrl; - QUrl accessTokenUrl; - QVector<quint16> listenerPorts = { 0 }; - }; - - /// Authorization flow types. - enum GrantFlow { - GrantFlowAuthorizationCode, ///< @see http://tools.ietf.org/html/draft-ietf-oauth-v2-15#section-4.1 - GrantFlowImplicit, ///< @see http://tools.ietf.org/html/draft-ietf-oauth-v2-15#section-4.2 - GrantFlowResourceOwnerPasswordCredentials, - GrantFlowDevice ///< @see https://tools.ietf.org/html/rfc8628#section-1 - }; - - /// Authorization flow. - GrantFlow grantFlow(); - void setGrantFlow(GrantFlow value); - -public: - /// Are we authenticated? - bool linked(); - - /// Authentication token. - QString token(); - - /// Provider-specific extra tokens, available after a successful authentication - QVariantMap extraTokens(); - - /// Page content on local host after successful oauth. - /// Provide it in case you do not want to close the browser, but display something - QByteArray replyContent() const; - void setReplyContent(const QByteArray &value); - -public: - - // TODO: remove - /// Resource owner username. - /// instances with the same (username, password) share the same "linked" and "token" properties. - QString username(); - void setUsername(const QString &value); - - // TODO: remove - /// Resource owner password. - /// instances with the same (username, password) share the same "linked" and "token" properties. - QString password(); - void setPassword(const QString &value); - - // TODO: remove - /// API key. - QString apiKey(); - void setApiKey(const QString &value); - - // TODO: remove - /// Allow ignoring SSL errors? - /// E.g. SurveyMonkey fails on Mac due to SSL error. Ignoring the error circumvents the problem - bool ignoreSslErrors(); - void setIgnoreSslErrors(bool ignoreSslErrors); - - // TODO: put in `Options` - /// User-defined extra parameters to append to request URL - QVariantMap extraRequestParams(); - void setExtraRequestParams(const QVariantMap &value); - - // TODO: split up the class into multiple, each implementing one OAuth2 flow - /// Grant type (if non-standard) - QString grantType(); - void setGrantType(const QString &value); - -public: - /// Constructor. - /// @param parent Parent object. - explicit OAuth2(Options & opts, Token & token, QObject *parent = 0, QNetworkAccessManager *manager = 0); - - /// Get refresh token. - QString refreshToken(); - - /// Get token expiration time - QDateTime expires(); - -public slots: - /// Authenticate. - virtual void link(); - - /// De-authenticate. - virtual void unlink(); - - /// Refresh token. - bool refresh(); - - /// Handle situation where reply server has opted to close its connection - void serverHasClosed(bool paramsfound = false); - -signals: - /// Emitted when a token refresh has been completed or failed. - void refreshFinished(QNetworkReply::NetworkError error); - - /// Emitted when client needs to open a web browser window, with the given URL. - void openBrowser(const QUrl &url); - - /// Emitted when client can close the browser window. - void closeBrowser(); - - /// Emitted when client needs to show a verification uri and user code - void showVerificationUriAndCode(const QUrl &uri, const QString &code, int expiresIn); - - /// Emitted when authentication/deauthentication succeeded. - void linkingSucceeded(); - - /// Emitted when authentication/deauthentication failed. - void linkingFailed(); - - void activityChanged(Activity activity); - -public slots: - /// Handle verification response. - virtual void onVerificationReceived(QMap<QString, QString>); - -protected slots: - /// Handle completion of a token request. - virtual void onTokenReplyFinished(); - - /// Handle failure of a token request. - virtual void onTokenReplyError(QNetworkReply::NetworkError error); - - /// Handle completion of a refresh request. - virtual void onRefreshFinished(); - - /// Handle failure of a refresh request. - virtual void onRefreshError(QNetworkReply::NetworkError error); - - /// Handle completion of a Device Authorization Request - virtual void onDeviceAuthReplyFinished(); - -protected: - /// Build HTTP request body. - QByteArray buildRequestBody(const QMap<QString, QString> ¶meters); - - /// Set refresh token. - void setRefreshToken(const QString &v); - - /// Set token expiration time. - void setExpires(QDateTime v); - - /// Start polling authorization server - void startPollServer(const QVariantMap ¶ms, int expiresIn); - - /// Set authentication token. - void setToken(const QString &v); - - /// Set the linked state - void setLinked(bool v); - - /// Set extra tokens found in OAuth response - void setExtraTokens(QVariantMap extraTokens); - - /// Set local reply server - void setReplyServer(ReplyServer *server); - - ReplyServer * replyServer() const; - - /// Set local poll server - void setPollServer(PollServer *server); - - PollServer * pollServer() const; - - void updateActivity(Activity activity); - -protected: - QString username_; - QString password_; - - Options options_; - - QVariantMap extraReqParams_; - QString apiKey_; - QNetworkAccessManager *manager_ = nullptr; - ReplyList timedReplies_; - GrantFlow grantFlow_; - QString grantType_; - -protected: - QString redirectUri_; - Token &token_; - - // this should be part of the reply server impl - QByteArray replyContent_; - -private: - ReplyServer *replyServer_ = nullptr; - PollServer *pollServer_ = nullptr; - Activity activity_ = Activity::Idle; -}; - -} diff --git a/libraries/katabasis/include/katabasis/Reply.h b/libraries/katabasis/include/katabasis/Reply.h index 3af1d49f..415cf4ec 100644 --- a/libraries/katabasis/include/katabasis/Reply.h +++ b/libraries/katabasis/include/katabasis/Reply.h @@ -9,12 +9,14 @@ namespace Katabasis { +constexpr int defaultTimeout = 30 * 1000; + /// A network request/reply pair that can time out. class Reply: public QTimer { Q_OBJECT public: - Reply(QNetworkReply *reply, int timeOut = 60 * 1000, QObject *parent = 0); + Reply(QNetworkReply *reply, int timeOut = defaultTimeout, QObject *parent = 0); signals: void error(QNetworkReply::NetworkError); @@ -25,6 +27,7 @@ public slots: public: QNetworkReply *reply; + bool timedOut = false; }; /// List of O2Replies. @@ -37,7 +40,7 @@ public: virtual ~ReplyList(); /// Create a new O2Reply from a QNetworkReply, and add it to this list. - void add(QNetworkReply *reply); + void add(QNetworkReply *reply, int timeOut = defaultTimeout); /// Add an O2Reply to the list, while taking ownership of it. void add(Reply *reply); diff --git a/libraries/katabasis/include/katabasis/ReplyServer.h b/libraries/katabasis/include/katabasis/ReplyServer.h deleted file mode 100644 index bf47df69..00000000 --- a/libraries/katabasis/include/katabasis/ReplyServer.h +++ /dev/null @@ -1,53 +0,0 @@ -#pragma once - -#include <QTcpServer> -#include <QMap> -#include <QByteArray> -#include <QString> - -namespace Katabasis { - -/// HTTP server to process authentication response. -class ReplyServer: public QTcpServer { - Q_OBJECT - -public: - explicit ReplyServer(QObject *parent = 0); - - /// Page content on local host after successful oauth - in case you do not want to close the browser, but display something - Q_PROPERTY(QByteArray replyContent READ replyContent WRITE setReplyContent) - QByteArray replyContent(); - void setReplyContent(const QByteArray &value); - - /// Seconds to keep listening *after* first response for a callback with token content - Q_PROPERTY(int timeout READ timeout WRITE setTimeout) - int timeout(); - void setTimeout(int timeout); - - /// Maximum number of callback tries to accept, in case some don't have token content (favicons, etc.) - Q_PROPERTY(int callbackTries READ callbackTries WRITE setCallbackTries) - int callbackTries(); - void setCallbackTries(int maxtries); - - QString uniqueState(); - void setUniqueState(const QString &state); - -signals: - void verificationReceived(QMap<QString, QString>); - void serverClosed(bool); // whether it has found parameters - -public slots: - void onIncomingConnection(); - void onBytesReady(); - QMap<QString, QString> parseQueryParams(QByteArray *data); - void closeServer(QTcpSocket *socket = 0, bool hasparameters = false); - -protected: - QByteArray replyContent_; - int timeout_; - int maxtries_; - int tries_; - QString uniqueState_; -}; - -} |