[Libreoffice-commits] online.git: 4 commits - loleaflet/debug loleaflet/dist loleaflet/main.js test/Makefile.am test/test.cpp test/UnitOAuth.cpp test/WhiteBoxTests.cpp wsd/Auth.cpp wsd/Auth.hpp wsd/ClientSession.cpp wsd/ClientSession.hpp wsd/DocumentBroker.cpp wsd/FileServer.cpp wsd/Storage.cpp wsd/Storage.hpp
Jan Holesovsky
kendy at collabora.com
Thu Aug 17 12:06:43 UTC 2017
loleaflet/debug/document/loleaflet.html | 5 +
loleaflet/dist/loleaflet.html | 1
loleaflet/main.js | 3 +
test/Makefile.am | 3 -
test/UnitOAuth.cpp | 85 +++++++++++++++++++++-----------
test/WhiteBoxTests.cpp | 45 ++++++++++++++++
test/test.cpp | 4 -
wsd/Auth.cpp | 56 +++++++++++++++++++++
wsd/Auth.hpp | 40 ++++++++++++++-
wsd/ClientSession.cpp | 14 ++++-
wsd/ClientSession.hpp | 2
wsd/DocumentBroker.cpp | 8 +--
wsd/FileServer.cpp | 6 +-
wsd/Storage.cpp | 45 +++++-----------
wsd/Storage.hpp | 18 +++---
15 files changed, 253 insertions(+), 82 deletions(-)
New commits:
commit a3a3d0ad6c3358a47c178185da6c2348e3374f21
Author: Jan Holesovsky <kendy at collabora.com>
Date: Thu Aug 17 14:05:22 2017 +0200
Fix various nitpicks.
Change-Id: I41fe795bc1ea7c73527c7e1183de7098517bad7a
diff --git a/test/UnitOAuth.cpp b/test/UnitOAuth.cpp
index ed82982e..7a52c1ee 100644
--- a/test/UnitOAuth.cpp
+++ b/test/UnitOAuth.cpp
@@ -28,20 +28,21 @@ using Poco::Net::OAuth20Credentials;
class UnitOAuth : public UnitWSD
{
- enum class Phase {
- Load0, // loading the document with Bearer token
- Load1, // loading the document with Basic auth
- Polling // let the loading progress, and when it succeeds, finish
+ enum class Phase
+ {
+ LoadToken, // loading the document with Bearer token
+ LoadHeader, // loading the document with Basic auth
+ Polling // let the loading progress, and when it succeeds, finish
} _phase;
- bool _finished0;
- bool _finished1;
+ bool _finishedToken;
+ bool _finishedHeader;
public:
UnitOAuth() :
- _phase(Phase::Load0),
- _finished0(false),
- _finished1(false)
+ _phase(Phase::LoadToken),
+ _finishedToken(false),
+ _finishedHeader(false)
{
}
@@ -123,12 +124,12 @@ public:
if (uriReq.getPath() == "/wopi/files/0/contents")
{
assertRequest(request, 0);
- _finished0 = true;
+ _finishedToken = true;
}
else
{
assertRequest(request, 1);
- _finished1 = true;
+ _finishedHeader = true;
}
const std::string mimeType = "text/plain; charset=utf-8";
@@ -145,7 +146,7 @@ public:
socket->send(oss.str());
socket->shutdown();
- if (_finished0 && _finished1)
+ if (_finishedToken && _finishedHeader)
exitTest(TestResult::Ok);
return true;
@@ -160,11 +161,11 @@ public:
switch (_phase)
{
- case Phase::Load0:
- case Phase::Load1:
+ case Phase::LoadToken:
+ case Phase::LoadHeader:
{
Poco::URI wopiURL(helpers::getTestServerURI() +
- ((_phase == Phase::Load0)? "/wopi/files/0?access_token=s3hn3ct0k3v":
+ ((_phase == Phase::LoadToken)? "/wopi/files/0?access_token=s3hn3ct0k3v":
"/wopi/files/1?access_header=Authorization: Basic basic=="));
//wopiURL.setPort(_wopiSocket->address().port());
std::string wopiSrc;
@@ -178,8 +179,8 @@ public:
helpers::sendTextFrame(*ws->getLOOLWebSocket(), "load url=" + wopiSrc, testName);
- if (_phase == Phase::Load0)
- _phase = Phase::Load1;
+ if (_phase == Phase::LoadToken)
+ _phase = Phase::LoadHeader;
else
_phase = Phase::Polling;
break;
diff --git a/test/WhiteBoxTests.cpp b/test/WhiteBoxTests.cpp
index adab5ed0..7c9b13f2 100644
--- a/test/WhiteBoxTests.cpp
+++ b/test/WhiteBoxTests.cpp
@@ -427,15 +427,15 @@ void WhiteBoxTests::testAuthorization()
Authorization auth1(Authorization::Type::Token, "abc");
Poco::URI uri1("http://localhost");
auth1.authorizeURI(uri1);
- CPPUNIT_ASSERT_EQUAL(uri1.toString(), std::string("http://localhost/?access_token=abc"));
+ CPPUNIT_ASSERT_EQUAL(std::string("http://localhost/?access_token=abc"), uri1.toString());
Poco::Net::HTTPRequest req1;
auth1.authorizeRequest(req1);
- CPPUNIT_ASSERT_EQUAL(req1.get("Authorization"), std::string("Bearer abc"));
+ CPPUNIT_ASSERT_EQUAL(std::string("Bearer abc"), req1.get("Authorization"));
Authorization auth1modify(Authorization::Type::Token, "modified");
// still the same uri1, currently "http://localhost/?access_token=abc"
auth1modify.authorizeURI(uri1);
- CPPUNIT_ASSERT_EQUAL(uri1.toString(), std::string("http://localhost/?access_token=modified"));
+ CPPUNIT_ASSERT_EQUAL(std::string("http://localhost/?access_token=modified"), uri1.toString());
Authorization auth2(Authorization::Type::Header, "def");
Poco::Net::HTTPRequest req2;
@@ -446,22 +446,22 @@ void WhiteBoxTests::testAuthorization()
Poco::URI uri2("http://localhost");
auth3.authorizeURI(uri2);
// nothing added with the Authorization header approach
- CPPUNIT_ASSERT_EQUAL(uri2.toString(), std::string("http://localhost"));
+ CPPUNIT_ASSERT_EQUAL(std::string("http://localhost"), uri2.toString());
Poco::Net::HTTPRequest req3;
auth3.authorizeRequest(req3);
- CPPUNIT_ASSERT_EQUAL(req3.get("Authorization"), std::string("Basic huhu=="));
+ CPPUNIT_ASSERT_EQUAL(std::string("Basic huhu=="), req3.get("Authorization"));
Authorization auth4(Authorization::Type::Header, " Authorization: Basic blah== \n\r X-Something: additional ");
Poco::Net::HTTPRequest req4;
auth4.authorizeRequest(req4);
- CPPUNIT_ASSERT_EQUAL(req4.get("Authorization"), std::string("Basic blah=="));
- CPPUNIT_ASSERT_EQUAL(req4.get("X-Something"), std::string("additional"));
+ CPPUNIT_ASSERT_EQUAL(std::string("Basic blah=="), req4.get("Authorization"));
+ CPPUNIT_ASSERT_EQUAL(std::string("additional"), req4.get("X-Something"));
Authorization auth5(Authorization::Type::Header, " Authorization: Basic huh== \n\r X-Something-More: else \n\r");
Poco::Net::HTTPRequest req5;
auth5.authorizeRequest(req5);
- CPPUNIT_ASSERT_EQUAL(req5.get("Authorization"), std::string("Basic huh=="));
- CPPUNIT_ASSERT_EQUAL(req5.get("X-Something-More"), std::string("else"));
+ CPPUNIT_ASSERT_EQUAL(std::string("Basic huh=="), req5.get("Authorization"));
+ CPPUNIT_ASSERT_EQUAL(std::string("else"), req5.get("X-Something-More"));
}
CPPUNIT_TEST_SUITE_REGISTRATION(WhiteBoxTests);
diff --git a/wsd/Auth.hpp b/wsd/Auth.hpp
index de41aeb6..98c0a2ce 100644
--- a/wsd/Auth.hpp
+++ b/wsd/Auth.hpp
@@ -23,7 +23,8 @@
class Authorization
{
public:
- enum class Type {
+ enum class Type
+ {
None,
Token,
Header
@@ -73,7 +74,8 @@ public:
_aud(aud),
_key(Poco::Crypto::RSAKey("", keyPath)),
_digestEngine(_key, "SHA256")
- { }
+ {
+ }
const std::string getAccessToken() override;
commit d78c0b164b3ae8278d51d453a16a69aefe4fec2a
Author: Jan Holesovsky <kendy at collabora.com>
Date: Thu Aug 17 14:04:22 2017 +0200
unit tests: Really bail out on error; and no need for a tempfile.
Change-Id: I53c1ab62bf9293217a5cada54c358292364ed60a
diff --git a/test/Makefile.am b/test/Makefile.am
index 5f7b769d..005618de 100644
--- a/test/Makefile.am
+++ b/test/Makefile.am
@@ -98,4 +98,4 @@ all-local: unittest
@echo "Running build-time unit tests. For more thorough testing, please run 'make check'."
@echo
@fc-cache "@LO_PATH@"/share/fonts/truetype
- @${top_builddir}/test/unittest 2> unittest.log || { cat unittest.log ; exit 1 ; }
+ @${top_builddir}/test/unittest
diff --git a/test/test.cpp b/test/test.cpp
index ed2f15af..e989e3fa 100644
--- a/test/test.cpp
+++ b/test/test.cpp
@@ -65,7 +65,7 @@ int main(int argc, char** argv)
Log::initialize("tst", loglevel, true, false, {});
- runClientTests(true, verbose);
+ return runClientTests(true, verbose)? 0: 1;
}
static bool IsStandalone = false;
@@ -134,7 +134,7 @@ bool runClientTests(bool standalone, bool verbose)
outputter.setNoWrap();
outputter.write();
- return result.wasSuccessful() ? 0 : 1;
+ return result.wasSuccessful();
}
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
commit f8ca17278f8d1114e37e656025bbf0bac2d59cc7
Author: Jan Holesovsky <kendy at collabora.com>
Date: Thu Aug 17 11:47:14 2017 +0200
access_header: Pass the access_header around + unit test.
Change-Id: I5d6d93e289d8faceda59deae128e8124a0193d95
Reviewed-on: https://gerrit.libreoffice.org/41243
Reviewed-by: Miklos Vajna <vmiklos at collabora.co.uk>
Reviewed-by: pranavk <pranavk at collabora.co.uk>
Tested-by: Jan Holesovsky <kendy at collabora.com>
diff --git a/loleaflet/debug/document/loleaflet.html b/loleaflet/debug/document/loleaflet.html
index 33364cea..fc239f3b 100644
--- a/loleaflet/debug/document/loleaflet.html
+++ b/loleaflet/debug/document/loleaflet.html
@@ -92,9 +92,14 @@
<script>
var wopiSrc = getParameterByName('WOPISrc');
var access_token = '%ACCESS_TOKEN%';
+ var access_header = '%ACCESS_HEADER%';
if (wopiSrc !== '' && access_token !== '') {
wopiSrc += '?access_token=' + access_token;
}
+ else if (wopiSrc !== '' && access_header !== '') {
+ wopiSrc += '?access_header=' + access_header;
+ }
+
var filePath = getParameterByName('file_path');
var title = getParameterByName('title');
diff --git a/loleaflet/dist/loleaflet.html b/loleaflet/dist/loleaflet.html
index f4f5e541..13e60e54 100644
--- a/loleaflet/dist/loleaflet.html
+++ b/loleaflet/dist/loleaflet.html
@@ -91,6 +91,7 @@
window.host = '%HOST%';
window.access_token = '%ACCESS_TOKEN%';
window.access_token_ttl = '%ACCESS_TOKEN_TTL%';
+ window.access_header = '%ACCESS_HEADER%';
window.loleaflet_logging = '%LOLEAFLET_LOGGING%';
window.outOfFocusTimeoutSecs = %OUT_OF_FOCUS_TIMEOUT_SECS%;
window.idleTimeoutSecs = %IDLE_TIMEOUT_SECS%;
diff --git a/loleaflet/main.js b/loleaflet/main.js
index 48200cd9..42660a13 100644
--- a/loleaflet/main.js
+++ b/loleaflet/main.js
@@ -60,6 +60,9 @@ var wopiSrc = getParameterByName('WOPISrc');
if (wopiSrc !== '' && access_token !== '') {
var wopiParams = { 'access_token': access_token, 'access_token_ttl': access_token_ttl };
}
+else if (wopiSrc !== '' && access_header !== '') {
+ var wopiParams = { 'access_header': access_header };
+}
var filePath = getParameterByName('file_path');
var title = getParameterByName('title');
diff --git a/test/UnitOAuth.cpp b/test/UnitOAuth.cpp
index 0136d0c8..ed82982e 100644
--- a/test/UnitOAuth.cpp
+++ b/test/UnitOAuth.cpp
@@ -29,16 +29,44 @@ using Poco::Net::OAuth20Credentials;
class UnitOAuth : public UnitWSD
{
enum class Phase {
- Load, // loading the document
+ Load0, // loading the document with Bearer token
+ Load1, // loading the document with Basic auth
Polling // let the loading progress, and when it succeeds, finish
} _phase;
+ bool _finished0;
+ bool _finished1;
+
public:
UnitOAuth() :
- _phase(Phase::Load)
+ _phase(Phase::Load0),
+ _finished0(false),
+ _finished1(false)
{
}
+ void assertRequest(const Poco::Net::HTTPRequest& request, int fileIndex)
+ {
+ // check that the request contains the Authorization: header
+ try {
+ if (fileIndex == 0)
+ {
+ OAuth20Credentials creds(request);
+ CPPUNIT_ASSERT_EQUAL(std::string("s3hn3ct0k3v"), creds.getBearerToken());
+ }
+ else
+ {
+ OAuth20Credentials creds(request, "Basic");
+ CPPUNIT_ASSERT_EQUAL(std::string("basic=="), creds.getBearerToken());
+ }
+ }
+ catch (const std::exception&)
+ {
+ // fail as fast as possible
+ exit(1);
+ }
+ }
+
/// Here we act as a WOPI server, so that we have a server that responds to
/// the wopi requests without additional expensive setup.
virtual bool handleHttpRequest(const Poco::Net::HTTPRequest& request, std::shared_ptr<StreamSocket>& socket) override
@@ -49,20 +77,11 @@ public:
LOG_INF("Fake wopi host request: " << uriReq.toString());
// CheckFileInfo
- if (uriReq.getPath() == "/wopi/files/0")
+ if (uriReq.getPath() == "/wopi/files/0" || uriReq.getPath() == "/wopi/files/1")
{
- LOG_INF("Fake wopi host request, handling CheckFileInfo.");
+ LOG_INF("Fake wopi host request, handling CheckFileInfo: " << uriReq.getPath());
- // check that the request contains the Authorization: header
- try {
- OAuth20Credentials creds(request);
- CPPUNIT_ASSERT_EQUAL(creds.getBearerToken(), std::string("s3hn3ct0k3v"));
- }
- catch (const std::exception&)
- {
- // fail as fast as possible
- exit(1);
- }
+ assertRequest(request, (uriReq.getPath() == "/wopi/files/0")? 0: 1);
Poco::LocalDateTime now;
Poco::JSON::Object::Ptr fileInfo = new Poco::JSON::Object();
@@ -97,19 +116,19 @@ public:
return true;
}
// GetFile
- else if (uriReq.getPath() == "/wopi/files/0/contents")
+ else if (uriReq.getPath() == "/wopi/files/0/contents" || uriReq.getPath() == "/wopi/files/1/contents")
{
- LOG_INF("Fake wopi host request, handling GetFile.");
+ LOG_INF("Fake wopi host request, handling GetFile: " << uriReq.getPath());
- // check that the request contains the Authorization: header
- try {
- OAuth20Credentials creds(request);
- CPPUNIT_ASSERT_EQUAL(creds.getBearerToken(), std::string("s3hn3ct0k3v"));
+ if (uriReq.getPath() == "/wopi/files/0/contents")
+ {
+ assertRequest(request, 0);
+ _finished0 = true;
}
- catch (const std::exception&)
+ else
{
- // fail as fast as possible
- exit(1);
+ assertRequest(request, 1);
+ _finished1 = true;
}
const std::string mimeType = "text/plain; charset=utf-8";
@@ -126,7 +145,8 @@ public:
socket->send(oss.str());
socket->shutdown();
- exitTest(TestResult::Ok);
+ if (_finished0 && _finished1)
+ exitTest(TestResult::Ok);
return true;
}
@@ -140,9 +160,12 @@ public:
switch (_phase)
{
- case Phase::Load:
+ case Phase::Load0:
+ case Phase::Load1:
{
- Poco::URI wopiURL(helpers::getTestServerURI() + "/wopi/files/0?access_token=s3hn3ct0k3v");
+ Poco::URI wopiURL(helpers::getTestServerURI() +
+ ((_phase == Phase::Load0)? "/wopi/files/0?access_token=s3hn3ct0k3v":
+ "/wopi/files/1?access_header=Authorization: Basic basic=="));
//wopiURL.setPort(_wopiSocket->address().port());
std::string wopiSrc;
Poco::URI::encode(wopiURL.toString(), ":/?", wopiSrc);
@@ -155,7 +178,10 @@ public:
helpers::sendTextFrame(*ws->getLOOLWebSocket(), "load url=" + wopiSrc, testName);
- _phase = Phase::Polling;
+ if (_phase == Phase::Load0)
+ _phase = Phase::Load1;
+ else
+ _phase = Phase::Polling;
break;
}
case Phase::Polling:
diff --git a/wsd/FileServer.cpp b/wsd/FileServer.cpp
index f6c3c74f..f27d9272 100644
--- a/wsd/FileServer.cpp
+++ b/wsd/FileServer.cpp
@@ -462,12 +462,15 @@ void FileServerRequestHandler::preprocessFile(const HTTPRequest& request, Poco::
const std::string& accessToken = form.get("access_token", "");
const std::string& accessTokenTtl = form.get("access_token_ttl", "");
LOG_TRC("access_token=" << accessToken << ", access_token_ttl=" << accessTokenTtl);
+ const std::string& accessHeader = form.get("access_header", "");
+ LOG_TRC("access_header=" << accessHeader);
// Escape bad characters in access token.
// This is placed directly in javascript in loleaflet.html, we need to make sure
// that no one can do anything nasty with their clever inputs.
- std::string escapedAccessToken;
+ std::string escapedAccessToken, escapedAccessHeader;
Poco::URI::encode(accessToken, "'", escapedAccessToken);
+ Poco::URI::encode(accessHeader, "'", escapedAccessHeader);
unsigned long tokenTtl = 0;
if (accessToken != "")
@@ -491,6 +494,7 @@ void FileServerRequestHandler::preprocessFile(const HTTPRequest& request, Poco::
Poco::replaceInPlace(preprocess, std::string("%ACCESS_TOKEN%"), escapedAccessToken);
Poco::replaceInPlace(preprocess, std::string("%ACCESS_TOKEN_TTL%"), std::to_string(tokenTtl));
+ Poco::replaceInPlace(preprocess, std::string("%ACCESS_HEADER%"), escapedAccessHeader);
Poco::replaceInPlace(preprocess, std::string("%HOST%"), host);
Poco::replaceInPlace(preprocess, std::string("%VERSION%"), std::string(LOOLWSD_VERSION_HASH));
commit afcfac4bef95cf7800effbc90818a0bfb8b434c2
Author: Jan Holesovsky <kendy at collabora.com>
Date: Wed Aug 16 16:38:00 2017 +0200
access_header: Infrastructure for providing custom headers for authentication.
Change-Id: I52e61dc01dbad0d501471e663aaf364d9bc23c52
Reviewed-on: https://gerrit.libreoffice.org/41223
Reviewed-by: Miklos Vajna <vmiklos at collabora.co.uk>
Reviewed-by: pranavk <pranavk at collabora.co.uk>
Tested-by: pranavk <pranavk at collabora.co.uk>
diff --git a/test/Makefile.am b/test/Makefile.am
index 9ff9bb44..5f7b769d 100644
--- a/test/Makefile.am
+++ b/test/Makefile.am
@@ -37,6 +37,7 @@ wsd_sources = \
../common/Util.cpp \
../common/MessageQueue.cpp \
../kit/Kit.cpp \
+ ../wsd/Auth.cpp \
../wsd/TileCache.cpp \
../wsd/TestStubs.cpp \
../common/Unit.cpp \
diff --git a/test/WhiteBoxTests.cpp b/test/WhiteBoxTests.cpp
index 7079c60a..adab5ed0 100644
--- a/test/WhiteBoxTests.cpp
+++ b/test/WhiteBoxTests.cpp
@@ -11,6 +11,7 @@
#include <cppunit/extensions/HelperMacros.h>
+#include <Auth.hpp>
#include <ChildSession.hpp>
#include <Common.hpp>
#include <Kit.hpp>
@@ -32,6 +33,7 @@ class WhiteBoxTests : public CPPUNIT_NS::TestFixture
CPPUNIT_TEST(testRegexListMatcher_Init);
CPPUNIT_TEST(testEmptyCellCursor);
CPPUNIT_TEST(testRectanglesIntersect);
+ CPPUNIT_TEST(testAuthorization);
CPPUNIT_TEST_SUITE_END();
@@ -43,6 +45,7 @@ class WhiteBoxTests : public CPPUNIT_NS::TestFixture
void testRegexListMatcher_Init();
void testEmptyCellCursor();
void testRectanglesIntersect();
+ void testAuthorization();
};
void WhiteBoxTests::testLOOLProtocolFunctions()
@@ -419,6 +422,48 @@ void WhiteBoxTests::testRectanglesIntersect()
1000, 1000, 2000, 1000));
}
+void WhiteBoxTests::testAuthorization()
+{
+ Authorization auth1(Authorization::Type::Token, "abc");
+ Poco::URI uri1("http://localhost");
+ auth1.authorizeURI(uri1);
+ CPPUNIT_ASSERT_EQUAL(uri1.toString(), std::string("http://localhost/?access_token=abc"));
+ Poco::Net::HTTPRequest req1;
+ auth1.authorizeRequest(req1);
+ CPPUNIT_ASSERT_EQUAL(req1.get("Authorization"), std::string("Bearer abc"));
+
+ Authorization auth1modify(Authorization::Type::Token, "modified");
+ // still the same uri1, currently "http://localhost/?access_token=abc"
+ auth1modify.authorizeURI(uri1);
+ CPPUNIT_ASSERT_EQUAL(uri1.toString(), std::string("http://localhost/?access_token=modified"));
+
+ Authorization auth2(Authorization::Type::Header, "def");
+ Poco::Net::HTTPRequest req2;
+ auth2.authorizeRequest(req2);
+ CPPUNIT_ASSERT(!req2.has("Authorization"));
+
+ Authorization auth3(Authorization::Type::Header, "Authorization: Basic huhu== ");
+ Poco::URI uri2("http://localhost");
+ auth3.authorizeURI(uri2);
+ // nothing added with the Authorization header approach
+ CPPUNIT_ASSERT_EQUAL(uri2.toString(), std::string("http://localhost"));
+ Poco::Net::HTTPRequest req3;
+ auth3.authorizeRequest(req3);
+ CPPUNIT_ASSERT_EQUAL(req3.get("Authorization"), std::string("Basic huhu=="));
+
+ Authorization auth4(Authorization::Type::Header, " Authorization: Basic blah== \n\r X-Something: additional ");
+ Poco::Net::HTTPRequest req4;
+ auth4.authorizeRequest(req4);
+ CPPUNIT_ASSERT_EQUAL(req4.get("Authorization"), std::string("Basic blah=="));
+ CPPUNIT_ASSERT_EQUAL(req4.get("X-Something"), std::string("additional"));
+
+ Authorization auth5(Authorization::Type::Header, " Authorization: Basic huh== \n\r X-Something-More: else \n\r");
+ Poco::Net::HTTPRequest req5;
+ auth5.authorizeRequest(req5);
+ CPPUNIT_ASSERT_EQUAL(req5.get("Authorization"), std::string("Basic huh=="));
+ CPPUNIT_ASSERT_EQUAL(req5.get("X-Something-More"), std::string("else"));
+}
+
CPPUNIT_TEST_SUITE_REGISTRATION(WhiteBoxTests);
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/wsd/Auth.cpp b/wsd/Auth.cpp
index 0def0fef..088719d7 100644
--- a/wsd/Auth.cpp
+++ b/wsd/Auth.cpp
@@ -37,6 +37,62 @@ using Poco::Base64Decoder;
using Poco::Base64Encoder;
using Poco::OutputLineEndingConverter;
+void Authorization::authorizeURI(Poco::URI& uri) const
+{
+ if (_type == Authorization::Type::Token)
+ {
+ static const std::string key("access_token");
+
+ Poco::URI::QueryParameters queryParams = uri.getQueryParameters();
+ for (auto& param: queryParams)
+ {
+ if (param.first == key)
+ {
+ param.second = _data;
+ uri.setQueryParameters(queryParams);
+ return;
+ }
+ }
+
+ // it did not exist yet
+ uri.addQueryParameter(key, _data);
+ }
+}
+
+void Authorization::authorizeRequest(Poco::Net::HTTPRequest& request) const
+{
+ switch (_type)
+ {
+ case Type::Token:
+ request.set("Authorization", "Bearer " + _data);
+ break;
+ case Type::Header:
+ {
+ // there might be more headers in here; like
+ // Authorization: Basic ....
+ // X-Something-Custom: Huh
+ Poco::StringTokenizer tokens(_data, "\n\r", Poco::StringTokenizer::TOK_IGNORE_EMPTY | Poco::StringTokenizer::TOK_TRIM);
+ for (const auto& token : tokens)
+ {
+ size_t i = token.find_first_of(':');
+ if (i != std::string::npos)
+ {
+ size_t separator = i;
+ for (++i; i < token.length() && token[i] == ' ';)
+ ++i;
+
+ // set the header
+ if (i < token.length())
+ request.set(token.substr(0, separator), token.substr(i));
+ }
+ }
+ break;
+ }
+ default:
+ assert(false);
+ }
+}
+
const std::string JWTAuth::getAccessToken()
{
std::string encodedHeader = createHeader();
diff --git a/wsd/Auth.hpp b/wsd/Auth.hpp
index 87aa54b7..de41aeb6 100644
--- a/wsd/Auth.hpp
+++ b/wsd/Auth.hpp
@@ -11,10 +11,46 @@
#ifndef INCLUDED_AUTH_HPP
#define INCLUDED_AUTH_HPP
+#include <cassert>
#include <string>
#include <Poco/Crypto/RSADigestEngine.h>
#include <Poco/Crypto/RSAKey.h>
+#include <Poco/Net/HTTPRequest.h>
+#include <Poco/URI.h>
+
+/// Class to keep the authorization data.
+class Authorization
+{
+public:
+ enum class Type {
+ None,
+ Token,
+ Header
+ };
+
+private:
+ Type _type;
+ std::string _data;
+
+public:
+ Authorization()
+ : _type(Type::None)
+ {
+ }
+
+ Authorization(Type type, const std::string& data)
+ : _type(type)
+ , _data(data)
+ {
+ }
+
+ /// Set the access_token parametr to the given uri.
+ void authorizeURI(Poco::URI& uri) const;
+
+ /// Set the Authorization: header in request.
+ void authorizeRequest(Poco::Net::HTTPRequest& request) const;
+};
/// Base class of all Authentication/Authorization implementations.
class AuthBase
diff --git a/wsd/ClientSession.cpp b/wsd/ClientSession.cpp
index d4793e96..77e05744 100644
--- a/wsd/ClientSession.cpp
+++ b/wsd/ClientSession.cpp
@@ -769,17 +769,25 @@ bool ClientSession::forwardToClient(const std::shared_ptr<Message>& payload)
return true;
}
-std::string ClientSession::getAccessToken() const
+Authorization ClientSession::getAuthorization() const
{
std::string accessToken;
Poco::URI::QueryParameters queryParams = _uriPublic.getQueryParameters();
+
+ // prefer the access_token
for (auto& param: queryParams)
{
if (param.first == "access_token")
- return param.second;
+ return Authorization(Authorization::Type::Token, param.second);
+ }
+
+ for (auto& param: queryParams)
+ {
+ if (param.first == "access_header")
+ return Authorization(Authorization::Type::Header, param.second);
}
- return std::string();
+ return Authorization();
}
void ClientSession::onDisconnect()
diff --git a/wsd/ClientSession.hpp b/wsd/ClientSession.hpp
index 0002d615..fd3a05b8 100644
--- a/wsd/ClientSession.hpp
+++ b/wsd/ClientSession.hpp
@@ -98,7 +98,7 @@ public:
const Poco::URI& getPublicUri() const { return _uriPublic; }
/// The access token of this session.
- std::string getAccessToken() const;
+ Authorization getAuthorization() const;
/// Set WOPI fileinfo object
void setWopiFileInfo(std::unique_ptr<WopiStorage::WOPIFileInfo>& wopiFileInfo) { _wopiFileInfo = std::move(wopiFileInfo); }
diff --git a/wsd/DocumentBroker.cpp b/wsd/DocumentBroker.cpp
index f697c663..7f294336 100644
--- a/wsd/DocumentBroker.cpp
+++ b/wsd/DocumentBroker.cpp
@@ -428,7 +428,7 @@ bool DocumentBroker::load(const std::shared_ptr<ClientSession>& session, const s
WopiStorage* wopiStorage = dynamic_cast<WopiStorage*>(_storage.get());
if (wopiStorage != nullptr)
{
- std::unique_ptr<WopiStorage::WOPIFileInfo> wopifileinfo = wopiStorage->getWOPIFileInfo(session->getAccessToken());
+ std::unique_ptr<WopiStorage::WOPIFileInfo> wopifileinfo = wopiStorage->getWOPIFileInfo(session->getAuthorization());
userid = wopifileinfo->_userid;
username = wopifileinfo->_username;
userExtraInfo = wopifileinfo->_userExtraInfo;
@@ -552,7 +552,7 @@ bool DocumentBroker::load(const std::shared_ptr<ClientSession>& session, const s
// Let's load the document now, if not loaded.
if (!_storage->isLoaded())
{
- const auto localPath = _storage->loadStorageFileToLocal(session->getAccessToken());
+ const auto localPath = _storage->loadStorageFileToLocal(session->getAuthorization());
std::ifstream istr(localPath, std::ios::binary);
Poco::SHA1Engine sha1;
@@ -639,7 +639,7 @@ bool DocumentBroker::saveToStorageInternal(const std::string& sessionId,
return false;
}
- const std::string accessToken = it->second->getAccessToken();
+ const Authorization auth = it->second->getAuthorization();
const auto uri = it->second->getPublicUri().toString();
// If we aren't destroying the last editable session just yet,
@@ -658,7 +658,7 @@ bool DocumentBroker::saveToStorageInternal(const std::string& sessionId,
LOG_DBG("Persisting [" << _docKey << "] after saving to URI [" << uri << "].");
assert(_storage && _tileCache);
- StorageBase::SaveResult storageSaveResult = _storage->saveLocalFileToStorage(accessToken);
+ StorageBase::SaveResult storageSaveResult = _storage->saveLocalFileToStorage(auth);
if (storageSaveResult == StorageBase::SaveResult::OK)
{
setModified(false);
diff --git a/wsd/Storage.cpp b/wsd/Storage.cpp
index 47c81748..72bae46a 100644
--- a/wsd/Storage.cpp
+++ b/wsd/Storage.cpp
@@ -246,7 +246,7 @@ std::unique_ptr<LocalStorage::LocalFileInfo> LocalStorage::getLocalFileInfo()
return std::unique_ptr<LocalStorage::LocalFileInfo>(new LocalFileInfo({"localhost" + std::to_string(LastLocalStorageId), "Local Host #" + std::to_string(LastLocalStorageId++)}));
}
-std::string LocalStorage::loadStorageFileToLocal(const std::string& /*accessToken*/)
+std::string LocalStorage::loadStorageFileToLocal(const Authorization& /*auth*/)
{
// /chroot/jailId/user/doc/childId/file.ext
const auto filename = Poco::Path(_uri.getPath()).getFileName();
@@ -297,7 +297,7 @@ std::string LocalStorage::loadStorageFileToLocal(const std::string& /*accessToke
#endif
}
-StorageBase::SaveResult LocalStorage::saveLocalFileToStorage(const std::string& /*accessToken*/)
+StorageBase::SaveResult LocalStorage::saveLocalFileToStorage(const Authorization& /*auth*/)
{
try
{
@@ -440,24 +440,6 @@ bool parseJSON(const std::string& json, Poco::JSON::Object::Ptr& object)
return success;
}
-void setQueryParameter(Poco::URI& uriObject, const std::string& key, const std::string& value)
-{
- Poco::URI::QueryParameters queryParams = uriObject.getQueryParameters();
- for (auto& param: queryParams)
- {
- if (param.first == key)
- {
- param.second = value;
- uriObject.setQueryParameters(queryParams);
- return;
- }
- }
-
- // it did not exist yet
- uriObject.addQueryParameter(key, value);
-}
-
-
void addStorageDebugCookie(Poco::Net::HTTPRequest& request)
{
(void) request;
@@ -499,11 +481,11 @@ Poco::Timestamp iso8601ToTimestamp(const std::string& iso8601Time)
} // anonymous namespace
-std::unique_ptr<WopiStorage::WOPIFileInfo> WopiStorage::getWOPIFileInfo(const std::string& accessToken)
+std::unique_ptr<WopiStorage::WOPIFileInfo> WopiStorage::getWOPIFileInfo(const Authorization& auth)
{
// update the access_token to the one matching to the session
Poco::URI uriObject(_uri);
- setQueryParameter(uriObject, "access_token", accessToken);
+ auth.authorizeURI(uriObject);
LOG_DBG("Getting info for wopi uri [" << uriObject.toString() << "].");
@@ -516,7 +498,7 @@ std::unique_ptr<WopiStorage::WOPIFileInfo> WopiStorage::getWOPIFileInfo(const st
Poco::Net::HTTPRequest request(Poco::Net::HTTPRequest::HTTP_GET, uriObject.getPathAndQuery(), Poco::Net::HTTPMessage::HTTP_1_1);
request.set("User-Agent", WOPI_AGENT_STRING);
- request.set("Authorization", "Bearer " + accessToken);
+ auth.authorizeRequest(request);
addStorageDebugCookie(request);
psession->sendRequest(request);
@@ -603,13 +585,14 @@ std::unique_ptr<WopiStorage::WOPIFileInfo> WopiStorage::getWOPIFileInfo(const st
}
/// uri format: http://server/<...>/wopi*/files/<id>/content
-std::string WopiStorage::loadStorageFileToLocal(const std::string& accessToken)
+std::string WopiStorage::loadStorageFileToLocal(const Authorization& auth)
{
// WOPI URI to download files ends in '/contents'.
// Add it here to get the payload instead of file info.
Poco::URI uriObject(_uri);
uriObject.setPath(uriObject.getPath() + "/contents");
- setQueryParameter(uriObject, "access_token", accessToken);
+ auth.authorizeURI(uriObject);
+
LOG_DBG("Wopi requesting: " << uriObject.toString());
const auto startTime = std::chrono::steady_clock::now();
@@ -619,7 +602,7 @@ std::string WopiStorage::loadStorageFileToLocal(const std::string& accessToken)
Poco::Net::HTTPRequest request(Poco::Net::HTTPRequest::HTTP_GET, uriObject.getPathAndQuery(), Poco::Net::HTTPMessage::HTTP_1_1);
request.set("User-Agent", WOPI_AGENT_STRING);
- request.set("Authorization", "Bearer " + accessToken);
+ auth.authorizeRequest(request);
addStorageDebugCookie(request);
psession->sendRequest(request);
@@ -670,14 +653,14 @@ std::string WopiStorage::loadStorageFileToLocal(const std::string& accessToken)
return "";
}
-StorageBase::SaveResult WopiStorage::saveLocalFileToStorage(const std::string& accessToken)
+StorageBase::SaveResult WopiStorage::saveLocalFileToStorage(const Authorization& auth)
{
// TODO: Check if this URI has write permission (canWrite = true)
const auto size = getFileSize(_jailedFilePath);
Poco::URI uriObject(_uri);
uriObject.setPath(uriObject.getPath() + "/contents");
- setQueryParameter(uriObject, "access_token", accessToken);
+ auth.authorizeURI(uriObject);
LOG_INF("Uploading URI via WOPI [" << uriObject.toString() << "] from [" << _jailedFilePath + "].");
@@ -689,7 +672,7 @@ StorageBase::SaveResult WopiStorage::saveLocalFileToStorage(const std::string& a
Poco::Net::HTTPRequest request(Poco::Net::HTTPRequest::HTTP_POST, uriObject.getPathAndQuery(), Poco::Net::HTTPMessage::HTTP_1_1);
request.set("X-WOPI-Override", "PUT");
- request.set("Authorization", "Bearer " + accessToken);
+ auth.authorizeRequest(request);
if (!_forceSave)
{
// Request WOPI host to not overwrite if timestamps mismatch
@@ -768,14 +751,14 @@ StorageBase::SaveResult WopiStorage::saveLocalFileToStorage(const std::string& a
return saveResult;
}
-std::string WebDAVStorage::loadStorageFileToLocal(const std::string& /*accessToken*/)
+std::string WebDAVStorage::loadStorageFileToLocal(const Authorization& /*auth*/)
{
// TODO: implement webdav GET.
_isLoaded = true;
return _uri.toString();
}
-StorageBase::SaveResult WebDAVStorage::saveLocalFileToStorage(const std::string& /*accessToken*/)
+StorageBase::SaveResult WebDAVStorage::saveLocalFileToStorage(const Authorization& /*auth*/)
{
// TODO: implement webdav PUT.
return StorageBase::SaveResult::OK;
diff --git a/wsd/Storage.hpp b/wsd/Storage.hpp
index 09002bde..6b26c066 100644
--- a/wsd/Storage.hpp
+++ b/wsd/Storage.hpp
@@ -101,10 +101,10 @@ public:
/// Returns a local file path for the given URI.
/// If necessary copies the file locally first.
- virtual std::string loadStorageFileToLocal(const std::string& accessToken) = 0;
+ virtual std::string loadStorageFileToLocal(const Authorization& auth) = 0;
/// Writes the contents of the file back to the source.
- virtual SaveResult saveLocalFileToStorage(const std::string& accessToken) = 0;
+ virtual SaveResult saveLocalFileToStorage(const Authorization& auth) = 0;
static size_t getFileSize(const std::string& filename);
@@ -168,9 +168,9 @@ public:
/// obtained using getFileInfo method
std::unique_ptr<LocalFileInfo> getLocalFileInfo();
- std::string loadStorageFileToLocal(const std::string& accessToken) override;
+ std::string loadStorageFileToLocal(const Authorization& auth) override;
- SaveResult saveLocalFileToStorage(const std::string& accessToken) override;
+ SaveResult saveLocalFileToStorage(const Authorization& auth) override;
private:
/// True if the jailed file is not linked but copied.
@@ -256,12 +256,12 @@ public:
/// provided during the initial creation of the WOPI storage.
/// Also extracts the basic file information from the response
/// which can then be obtained using getFileInfo()
- std::unique_ptr<WOPIFileInfo> getWOPIFileInfo(const std::string& accessToken);
+ std::unique_ptr<WOPIFileInfo> getWOPIFileInfo(const Authorization& auth);
/// uri format: http://server/<...>/wopi*/files/<id>/content
- std::string loadStorageFileToLocal(const std::string& accessToken) override;
+ std::string loadStorageFileToLocal(const Authorization& auth) override;
- SaveResult saveLocalFileToStorage(const std::string& accessToken) override;
+ SaveResult saveLocalFileToStorage(const Authorization& auth) override;
/// Total time taken for making WOPI calls during load
std::chrono::duration<double> getWopiLoadDuration() const { return _wopiLoadDuration; }
@@ -289,9 +289,9 @@ public:
// Implement me
// WebDAVFileInfo getWebDAVFileInfo(const Poco::URI& uriPublic);
- std::string loadStorageFileToLocal(const std::string& accessToken) override;
+ std::string loadStorageFileToLocal(const Authorization& auth) override;
- SaveResult saveLocalFileToStorage(const std::string& accessToken) override;
+ SaveResult saveLocalFileToStorage(const Authorization& auth) override;
private:
std::unique_ptr<AuthBase> _authAgent;
More information about the Libreoffice-commits
mailing list