Skip to content
Permalink
Browse files

Merge pull request #7310 from elpaso/oauth2

[auth] OAuth2 authentication plugin
  • Loading branch information
elpaso committed Jun 27, 2018
2 parents 602a858 + f2245ef commit efe0fbf9dbe100c8433d964bfff99ac035e6595a
Showing with 13,115 additions and 31 deletions.
  1. +2 −1 .ci/travis/macos/before_install.sh
  2. +2 −0 .docker/qgis3-build-deps.dockerfile
  3. +2 −0 doc/modules.dox
  4. +26 −0 external/o2/CHANGES.md
  5. +56 −0 external/o2/CMakeLists.txt
  6. +23 −0 external/o2/LICENSE
  7. +223 −0 external/o2/README.md
  8. +4 −0 external/o2/README_QGIS.txt
  9. +81 −0 external/o2/acknowledgements.md
  10. +38 −0 external/o2/cmake/modules/FindQt5Keychain.cmake
  11. +39 −0 external/o2/cmake/modules/FindQtKeychain.cmake
  12. +6 −0 external/o2/examples/.gitignore
  13. +13 −0 external/o2/examples/CMakeLists.txt
  14. +43 −0 external/o2/examples/facebookdemo/CMakeLists.txt
  15. +16 −0 external/o2/examples/facebookdemo/facebookdemo.pro
  16. +119 −0 external/o2/examples/facebookdemo/fbdemo.cpp
  17. +35 −0 external/o2/examples/facebookdemo/fbdemo.h
  18. +71 −0 external/o2/examples/facebookdemo/main.cpp
  19. +26 −0 external/o2/examples/implicit_redirect.html
  20. +73 −0 external/o2/examples/sialis/.gitignore
  21. +5 −0 external/o2/examples/sialis/README.md
  22. +13 −0 external/o2/examples/sialis/deployment.pri
  23. +19 −0 external/o2/examples/sialis/main.cpp
  24. +128 −0 external/o2/examples/sialis/main.qml
  25. +5 −0 external/o2/examples/sialis/qml.qrc
  26. BIN external/o2/examples/sialis/sialis.icns
  27. +24 −0 external/o2/examples/sialis/sialis.pro
  28. +40 −0 external/o2/examples/sialis/tweetmodel.cpp
  29. +38 −0 external/o2/examples/sialis/tweetmodel.h
  30. +57 −0 external/o2/examples/sialis/twitterapi.cpp
  31. +45 −0 external/o2/examples/sialis/twitterapi.h
  32. +43 −0 external/o2/examples/twitterdemo/CMakeLists.txt
  33. +111 −0 external/o2/examples/twitterdemo/main.cpp
  34. +135 −0 external/o2/examples/twitterdemo/tweeter.cpp
  35. +41 −0 external/o2/examples/twitterdemo/tweeter.h
  36. +14 −0 external/o2/examples/twitterdemo/twitterdemo.pro
  37. +10 −0 external/o2/o2.pc.cmake
  38. +229 −0 external/o2/src/CMakeLists.txt
  39. +24 −0 external/o2/src/o0abstractstore.h
  40. +126 −0 external/o2/src/o0baseauth.cpp
  41. +121 −0 external/o2/src/o0baseauth.h
  42. +12 −0 external/o2/src/o0export.h
  43. +62 −0 external/o2/src/o0globals.h
  44. +78 −0 external/o2/src/o0keychainstore.cpp
  45. +33 −0 external/o2/src/o0keychainstore.h
  46. +16 −0 external/o2/src/o0requestparameter.h
  47. +44 −0 external/o2/src/o0settingsstore.cpp
  48. +43 −0 external/o2/src/o0settingsstore.h
  49. +227 −0 external/o2/src/o0simplecrypt.h
  50. +389 −0 external/o2/src/o1.cpp
  51. +125 −0 external/o2/src/o1.h
  52. +19 −0 external/o2/src/o1dropbox.h
  53. +19 −0 external/o2/src/o1flickr.h
  54. +23 −0 external/o2/src/o1freshbooks.h
  55. +57 −0 external/o2/src/o1requestor.cpp
  56. +62 −0 external/o2/src/o1requestor.h
  57. +20 −0 external/o2/src/o1timedreply.cpp
  58. +27 −0 external/o2/src/o1timedreply.h
  59. +19 −0 external/o2/src/o1twitter.h
  60. +497 −0 external/o2/src/o2.cpp
  61. +181 −0 external/o2/src/o2.h
  62. +1 −0 external/o2/src/o2.pri
  63. +90 −0 external/o2/src/o2facebook.cpp
  64. +19 −0 external/o2/src/o2facebook.h
  65. +10 −0 external/o2/src/o2gft.cpp
  66. +15 −0 external/o2/src/o2gft.h
  67. +15 −0 external/o2/src/o2google.cpp
  68. +16 −0 external/o2/src/o2google.h
  69. +17 −0 external/o2/src/o2hubic.cpp
  70. +18 −0 external/o2/src/o2hubic.h
  71. +58 −0 external/o2/src/o2reply.cpp
  72. +61 −0 external/o2/src/o2reply.h
  73. +168 −0 external/o2/src/o2replyserver.cpp
  74. +50 −0 external/o2/src/o2replyserver.h
  75. +193 −0 external/o2/src/o2requestor.cpp
  76. +83 −0 external/o2/src/o2requestor.h
  77. +254 −0 external/o2/src/o2simplecrypt.cpp
  78. +125 −0 external/o2/src/o2skydrive.cpp
  79. +19 −0 external/o2/src/o2skydrive.h
  80. +42 −0 external/o2/src/o2spotify.cpp
  81. +32 −0 external/o2/src/o2spotify.h
  82. +21 −0 external/o2/src/o2surveymonkey.cpp
  83. +15 −0 external/o2/src/o2surveymonkey.h
  84. +69 −0 external/o2/src/oxtwitter.cpp
  85. +38 −0 external/o2/src/oxtwitter.h
  86. +47 −0 external/o2/src/src.pri
  87. +1 −1 scripts/astyle.sh
  88. +5 −0 src/auth/CMakeLists.txt
  89. +192 −0 src/auth/oauth2/CMakeLists.txt
  90. +66 −0 src/auth/oauth2/cmake/DownloadO2.cmake
  91. +59 −0 src/auth/oauth2/cmake/FindO2.cmake
  92. +51 −0 src/auth/oauth2/cmake/FindQtKeychain.cmake
  93. +27 −0 src/auth/oauth2/oauth2_config_samples/OAuth2-Github-authcode.json
  94. +27 −0 src/auth/oauth2/oauth2_config_samples/OAuth2-Google-authcode.json
  95. +26 −0 src/auth/oauth2/oauth2_config_samples/OAuth2-MyCompany-API-resowner.json
  96. +26 −0 src/auth/oauth2/oauth2_config_samples/OAuth2-PingFederate-implcit.json
  97. +19 −0 src/auth/oauth2/oauth2_config_samples/README.rst
  98. +12 −0 src/auth/oauth2/oauth2_resources.qrc
  99. +55 −0 src/auth/oauth2/oauth2_resources/close.svg
  100. +447 −0 src/auth/oauth2/oauth2_resources/export.svg
  101. +534 −0 src/auth/oauth2/oauth2_resources/fileopen.svg
  102. +1 −0 src/auth/oauth2/oauth2_resources/hidden.svg
  103. +447 −0 src/auth/oauth2/oauth2_resources/import.svg
  104. +1 −0 src/auth/oauth2/oauth2_resources/visible.svg
  105. +5 −0 src/auth/oauth2/oauth2_resources/visible_red.svg
  106. +25 −0 src/auth/oauth2/oauth2_verification_finished.html
  107. +817 −0 src/auth/oauth2/qgsauthoauth2config.cpp
  108. +381 −0 src/auth/oauth2/qgsauthoauth2config.h
  109. +914 −0 src/auth/oauth2/qgsauthoauth2edit.cpp
  110. +137 −0 src/auth/oauth2/qgsauthoauth2edit.h
  111. +978 −0 src/auth/oauth2/qgsauthoauth2edit.ui
  112. +678 −0 src/auth/oauth2/qgsauthoauth2method.cpp
  113. +106 −0 src/auth/oauth2/qgsauthoauth2method.h
  114. +132 −0 src/auth/oauth2/qgso2.cpp
  115. +69 −0 src/auth/oauth2/qgso2.h
  116. +160 −0 src/auth/oauth2/qjsonwrapper/Json.cpp
  117. +77 −0 src/auth/oauth2/qjsonwrapper/Json.h
  118. +21 −0 src/auth/oauth2/qjsonwrapper/LICENSE
  119. +7 −0 src/auth/oauth2/qjsonwrapper/README.md
  120. +1 −0 tests/src/CMakeLists.txt
  121. +74 −0 tests/src/auth/CMakeLists.txt
  122. +408 −0 tests/src/auth/testqgsauthoauth2method.cpp
  123. +3 −0 tests/src/python/CMakeLists.txt
  124. +298 −29 tests/src/python/qgis_wrapped_server.py
  125. +273 −0 tests/src/python/test_authmanager_oauth2_ows.py
@@ -28,7 +28,8 @@ pip3 install \
pyyaml \
mock \
future \
termcolor
termcolor \
oauthlib

brew install \
qscintilla2 \
@@ -106,6 +106,8 @@ RUN apt-get update \
future \
termcolor \
owslib \
oauthlib \
pyopenssl \
&& apt-get clean

RUN echo "alias python=python3" >> ~/.bash_aliases
@@ -42,3 +42,5 @@ Contains classes related to implementation of QGIS plugins.
The QgsQuick library is built on top of the CORE library and Qt Quick/QML framework. It adds reusable GUI Quick Components, mainly for mobile devices.

*/


@@ -0,0 +1,26 @@
# Change Log

## 1.0.1

* Add Spotify specialization
* Fix Skydrive specialization
* If available, use ```qml``` instead of ```script```
* Use ```Q_SIGNALS``` etc. instead of ```signals``` etc.
* Add versioning, shared library support
* Add Surveymonkey specialization
* Add DLL import/export declarations for Windows

## 1.0.0

* O1 and O2 to share a common base class
* Move common classes to the O0 name space
* Cleanups and bug fixes

## 0.1.0

* Add Sialis, a Qt Quick Twitter demo client
* Cleanups and bug fixes

## Pre-0.1.0

* Initial non-release
@@ -0,0 +1,56 @@
cmake_minimum_required(VERSION 2.8.11)

if(POLICY CMP0048) # in CMake >= 3.0.0
cmake_policy(SET CMP0048 OLD) # keep project() from clearing VERSION variables
endif(POLICY CMP0048)

set( CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake/modules )

set(VER_MAJOR "1")
set(VER_MINOR "0")
set(VER_PATCH "1")
set(API_VER_PATCH "0")
set(CPACK_PACKAGE_VERSION_MAJOR ${VER_MAJOR})
set(CPACK_PACKAGE_VERSION_MINOR ${VER_MINOR})
set(CPACK_PACKAGE_VERSION_PATCH ${VER_PATCH})
set(PROJECT_VERSION ${VER_MAJOR}.${VER_MINOR}.${VER_PATCH})
set(API_VERSION ${VER_MAJOR}.${VER_MINOR}.${API_VER_PATCH})

project(o2)

option(o2_WITH_QT5 "Use Qt5" ON)

set(o2_LIB_SUFFIX "" CACHE STRING "Suffix for install 'lib' directory, e.g. 64 for lib64")

option(o2_SHOW_TRACE "Show debugging messages" OFF)
if(NOT o2_SHOW_TRACE)
add_definitions(-DQT_NO_DEBUG_OUTPUT=1)
endif()

option(o2_WITH_TWITTER "Authenticate with Twitter" OFF)
option(o2_WITH_DROPBOX "Authenticate with Dropbox" OFF)
option(o2_WITH_GOOGLE "Authenticate with Google" OFF)
option(o2_WITH_FACEBOOK "Authenticate with Facebook" OFF)
option(o2_WITH_SKYDRIVE "Authenticate with SkyDrive" OFF)
option(o2_WITH_FLICKR "Authenticate with Flickr" OFF)
option(o2_WITH_HUBIC "Authenticate with Hubic" OFF)
option(o2_WITH_SPOTIFY "Authenticate with Spotify" OFF)
option(o2_WITH_SURVEYMONKEY "Authenticate with SurveyMonkey" OFF)
option(o2_WITH_KEYCHAIN "keychain store" ON)

option(o2_WITH_OAUTH1 "Include OAuth1 authentication" OFF)
if(o2_WITH_TWITTER OR o2_WITH_DROPBOX OR o2_WITH_FLICKR)
set(o2_WITH_OAUTH1 ON)
endif()

option(o2_BUILD_EXAMPLES "Build examples" OFF)

if(WIN32)
add_definitions(-DO2_DLL_EXPORT)
endif()

add_subdirectory(src)

if(o2_BUILD_EXAMPLES)
add_subdirectory(examples)
endif(o2_BUILD_EXAMPLES)
@@ -0,0 +1,23 @@
Copyright (c) 2012, Akos Polster
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

* Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.

* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
@@ -0,0 +1,223 @@
# OAuth 1.0 and 2.0 for Qt

This library encapsulates the OAuth 1.0 and 2.0 client authentication flows, and the sending of authenticated HTTP requests.

The primary target is Qt Quick applications on embedded devices.

Notes to contributors:

* Please follow the coding style of the existing source
* Code contributions are released under Simplified BSD License, as specified in LICENSE. Do not contribute if this license does not suit your code

## Classes

Class | Header | Purpose
:-- | :-- | :--
O0AbstractStore | o0abstractstore.h | Base class of persistent stores
O0BaseAuth | o0baseauth.h | Base class of OAuth authenticators
O0SettingsStore | o0settingsstore.h | QSettings-based persistent store
o0keyChainStore | o0keychainstore.h | Settings stored through the system keychain [keychain](https://github.com/frankosterfeld/qtkeychain)
O0SimpleCrypt | o0simplecrypt.h | Simple encryption and decryption by Andre Somers
O1 | o1.h | Generic OAuth 1.0 authenticator
O1Dropbox | o1dropbox.h | Dropbox OAuth specialization
O1Flickr | o1flickr.h | Flickr OAuth specialization
O1Freshbooks | o1freshbooks.h | Freshbooks OAuth specialization
O1Requestor | o1requestor.h | Makes authenticated OAuth 1.0 requests: GET, POST or PUT, handles timeouts
O1RequestParameter | o1.h | An extra request parameter participating in request signing
O1Twitter | o1twitter.h | Twitter OAuth specialization
O2 | o2.h | Generic OAuth 2.0 authenticator
O2Facebook | o2facebook.h | Facebook OAuth specialization
O2Gft | o2gft.h | Google Fusion Tables OAuth specialization
O2Google | o2google.h | Google Oauth specialization [scopes](https://developers.google.com/identity/protocols/googlescopes)
O2Hubic | o2hubic.h | Hubic OAuth specialization
O2Reply | o2reply.h | A network request/reply that can time out
O2ReplyServer | o2replyserver.h | HTTP server to process authentication responses
O2Requestor | o2requestor.h | Makes authenticated OAuth 2.0 requests (GET, POST or PUT), handles timeouts and token expiry
O2Skydrive | o2skydrive.h | OneDrive OAuth specialization
O2SurveyMonkey | o2surveymonkey.h | SurveyMonkey OAuth specialization
OXTwitter | oxtwitter.h | Twitter XAuth specialization

## Installation

Clone the Github repository, then add all files in *src* to your Qt project, by including *src/src.pri*.

## Basic Usage

This example assumes a hypothetical Twitter client that will post tweets. Twitter is using OAuth 1.0.

### Setup

Include the required header files, and have some member variables that will be used for authentication and sending requests:

#include "o1twitter.h"
#include "o1requestor.h"
O1Twitter *o1;

### Initialization

Instantiate one of the authenticator classes, like O1Twitter, set your application ID and application secret, and install the signal handlers:

o1 = new O1Twitter(this);
o1->setClientId(MY_CLIENT_ID);
o1->setClientSecret(MY_CLIENT_SECRET);
connect(o1, SIGNAL(linkedChanged()), this, SLOT(onLinkedChanged()));
connect(o1, SIGNAL(linkingFailed()), this, SLOT(onLinkingFailed()));
connect(o1, SIGNAL(linkingSucceeded()), this, SLOT(onLinkingSucceeded()));
connect(o1, SIGNAL(openBrowser(QUrl)), this, SLOT(onOpenBrowser(QUrl)));
connect(o1, SIGNAL(closeBrowser()), this, SLOT(onCloseBrowser()));

**Note:** For browserless Twitter authentication, you can use the OXTwitter specialized class which can do Twitter XAuth. You will need to additionally provide your Twitter login credentials (username & password) before calling *link()*.

### Handling Signals

O2 is an asynchronous library. It will send signals at various stages of authentication and request processing.

To handle these signals, implement the following slots in your code:

void onLinkedChanged() {
// Linking (login) state has changed.
// Use o1->linked() to get the actual state
}

void onLinkingFailed() {
// Login has failed
}

void onLinkingSucceeded() {
// Login has succeeded
}

void onOpenBrowser(const QUrl *url) {
// Open a web browser or a web view with the given URL.
// The user will interact with this browser window to
// enter login name, password, and authorize your application
// to access the Twitter account
}

void onCloseBrowser() {
// Close the browser window opened in openBrowser()
}

### Logging In

To log in (e.g. to link your application to the OAuth service), call the link() method:

o1->link();

This initiates the authentication sequence. Your signal handlers above will be called at various stages. Lastly, if linking succeeds, onLinkingSucceeded() will be called.

### Logging Out

To log out, call the unlink() method:

o1->unlink();

Logging out always succeeds, and requires no user interaction.

### Sending Authenticated Requests

Once linked, you can start sending authenticated requests to the service. We start with a simple example of sending a text-only tweet or as it's known in Twitter docs, a 'status update'.

First we need a Qt network manager and an O1 requestor object:

QNetworkAccessManager *manager = new QNetworkAccessManager(this);
O1Requestor *requestor = new O1Requestor(manager, o1, this);

Next, create parameters for posting the update:

QByteArray paramName("status");
QByteArray tweetText("My first tweet!");

QList<O1RequestParameter> requestParams = QList<O1RequestParameter>();
requestParams << O1RequestParameter(paramName, tweetText);

QByteArray postData = O1::createQueryParams(requestParams);

// Using Twitter's REST API ver 1.1
QUrl url = QUrl("https://api.twitter.com/1.1/statuses/update.json");

QNetworkRequest request(url);
request.setHeader(QNetworkRequest::ContentTypeHeader, O2_MIME_TYPE_XFORM);

Finally we authenticate and send the request using the O1 requestor object:

QNetworkReply *reply = requestor->post(request, reqestParams, postData);

Continuing with the example, we will now send a tweet containing an image as well as a message.

We create an HTTP request containing the image and the message, in the format specified by Twitter:

QString imagePath("/tmp/image.jpg");
QString message("My tweet with an image!");

QFileInfo fileInfo(imagePath);
QFile file(imagePath);
file.open(QIODevice::ReadOnly);

QString boundary("7d44e178b0439");
QByteArray data(QString("--" + boundary + "\r\n").toAscii());
data += "Content-Disposition: form-data; name=\"media[]\"; filename=\"" + fileInfo.fileName() + "\"\r\n";
data += "Content-Transfer-Encoding: binary\r\n";
data += "Content-Type: application/octet-stream\r\n\r\n";
data += file.readAll();
file.close();
data += QString("\r\n--") + boundary + "\r\n";
data += "Content-Disposition: form-data; name=\"status\"\r\n";
data += "Content-Transfer-Encoding: binary\r\n";
data += "Content-Type: text/plain; charset=utf-8\r\n\r\n";
data += message.toUtf8();
data += QString("\r\n--") + boundary + "--\r\n";

QNetworkRequest request;
// Using Twitter's REST API ver 1.1
request.setUrl(QUrl("https://api.twitter.com/1.1/statuses/update_with_media.json"));
request.setHeader(QNetworkRequest::ContentTypeHeader, "multipart/form-data; boundary=" + boundary);
request.setHeader(QNetworkRequest::ContentLengthHeader, data.length());

QNetworkReply *reply = requestor->post(request, QList<O1RequestParameter>(), data);

That's it. Tweets using the O2 library!

### Storing OAuth Tokens

O2 provides simple storage classes for writing OAuth tokens in a peristent location. Currently, a QSettings based backing store **O2SettingsStore** is provided in O2. O2SettingsStore keeps all token values in an encrypted form. You have to specify the encryption key to use while constructing the object:

O0SettingsStore settings = new O0SettingsStore("myencryptionkey");
// Set the store before starting OAuth, i.e before calling link()
o1->setStore(settings);
...

You can also create it with your customized QSettings object. O2SettingsStore will then use that QSettings object for storing the tokens:

O0SettingsStore settings = new O0SettingsStore(mySettingsObject, "myencryptionkey");

Once set, O2SettingsStore takes ownership of the QSettings object.

**Note:** If you do not specify a storage object to use, O2 will create one by default (which QSettings based), and use it. In such a case, a default encryption key is used for encrypting the data.

### Extra OAuth Tokens

Some OAuth service providers provide additional information in the access token response. Eg: Twitter returns 2 additional tokens in it's access token response - *screen_name* and *user_id*.

O2 provides all such tokens via the property - *extraTokens*. You can query this property after a successful OAuth exchange, i.e after the *linkingSucceeded()* signal has been emitted.

## More Examples

The *examples* folder contains complete example applications:

Name | Description
:-- | :--
facebookdemo | Command line application authenticating with Facebook
sialis | QT Quick Twitter client using OAuth 1
twitterdemo | Command line client for authenticating with Twitter and posting status updates. Uses OAuth 1 or Twitter XAuth

## Change Log

### 0.1.0

* Persist the extra tokens, too
* Add Qt Quick Twitter client example




@@ -0,0 +1,4 @@

O2 Library from https://github.com/pipacs/o2/archive/31ceafb3f0c3b605110ddd20aeebd3288504ee1f.tar.gz

Note: current master build of O2 is broken if built with keychain support

0 comments on commit efe0fbf

Please sign in to comment.
You can’t perform that action at this time.