added OAuth20Credentials class, some minor OAuth10Credentials fixes

This commit is contained in:
Guenter Obiltschnig
2014-11-11 12:10:53 +01:00
parent b0946115cf
commit fbcbf708aa
9 changed files with 402 additions and 14 deletions

View File

@@ -33,7 +33,7 @@ objects = \
NTPClient NTPEventArgs NTPPacket \ NTPClient NTPEventArgs NTPPacket \
RemoteSyslogChannel RemoteSyslogListener SMTPChannel \ RemoteSyslogChannel RemoteSyslogListener SMTPChannel \
WebSocket WebSocketImpl \ WebSocket WebSocketImpl \
OAuth10Credentials OAuth10Credentials OAuth20Credentials
target = PocoNet target = PocoNet
target_version = $(LIBVERSION) target_version = $(LIBVERSION)

View File

@@ -102,12 +102,12 @@ public:
/// Creates an empty OAuth10Credentials object. /// Creates an empty OAuth10Credentials object.
OAuth10Credentials(const std::string& consumerKey, const std::string& consumerSecret); OAuth10Credentials(const std::string& consumerKey, const std::string& consumerSecret);
/// Creates an HTTPCredentials object with the given consumer key and consumer secret. /// Creates an OAuth10Credentials object with the given consumer key and consumer secret.
/// ///
/// The token and tokenSecret will be left empty. /// The token and tokenSecret will be left empty.
OAuth10Credentials(const std::string& consumerKey, const std::string& consumerSecret, const std::string& token, const std::string& tokenSecret); OAuth10Credentials(const std::string& consumerKey, const std::string& consumerSecret, const std::string& token, const std::string& tokenSecret);
/// Creates an HTTPCredentials object with the given consumer key and /// Creates an OAuth10Credentials object with the given consumer key and
/// consumer secret, as well as token and token secret. /// consumer secret, as well as token and token secret.
explicit OAuth10Credentials(const HTTPRequest& request); explicit OAuth10Credentials(const HTTPRequest& request);
@@ -119,7 +119,7 @@ public:
/// not contain OAuth 1.0 credentials. /// not contain OAuth 1.0 credentials.
~OAuth10Credentials(); ~OAuth10Credentials();
/// Destroys the HTTPCredentials. /// Destroys the OAuth10Credentials.
void setConsumerKey(const std::string& consumerKey); void setConsumerKey(const std::string& consumerKey);
/// Sets the consumer key. /// Sets the consumer key.
@@ -195,6 +195,8 @@ public:
/// computed by createNonce() and the timestamp is taken /// computed by createNonce() and the timestamp is taken
/// from the system time. /// from the system time.
static const std::string SCHEME;
protected: protected:
void signPlaintext(Poco::Net::HTTPRequest& request) const; void signPlaintext(Poco::Net::HTTPRequest& request) const;
/// Signs the given HTTP request according to OAuth 1.0A PLAINTEXT signature method. /// Signs the given HTTP request according to OAuth 1.0A PLAINTEXT signature method.

View File

@@ -0,0 +1,121 @@
//
// OAuth20Credentials.h
//
// $Id$
//
// Library: Net
// Package: OAuth
// Module: OAuth20Credentials
//
// Definition of the OAuth20Credentials class.
//
// Copyright (c) 2014, Applied Informatics Software Engineering GmbH.
// and Contributors.
//
// SPDX-License-Identifier: BSL-1.0
//
#ifndef Net_OAuth20Credentials_INCLUDED
#define Net_OAuth20Credentials_INCLUDED
#include "Poco/Net/Net.h"
namespace Poco {
namespace Net {
class HTTPRequest;
class Net_API OAuth20Credentials
/// This class implements OAuth 2.0 authentication for HTTP requests,
/// via Bearer tokens in the Authorization header,
/// according to RFC 6749 and RFC 6750.
{
public:
OAuth20Credentials();
/// Creates an empty OAuth20Credentials object.
explicit OAuth20Credentials(const std::string& bearerToken);
/// Creates an OAuth20Credentials object with the given bearer token.
OAuth20Credentials(const std::string& bearerToken, const std::string& scheme);
/// Creates an OAuth20Credentials object with the given bearer token
/// and authorization scheme, which overrides the default scheme ("Bearer").
///
/// This is useful for services like GitHub, which use "token" as scheme.
explicit OAuth20Credentials(const HTTPRequest& request);
/// Creates an OAuth20Credentials object from a HTTPRequest object.
///
/// Extracts bearer token from the Authorization header, which
/// must use the "Bearer" authorization scheme.
///
/// Throws a NotAuthenticatedException if the request does
/// not contain a bearer token in the Authorization header.
OAuth20Credentials(const HTTPRequest& request, const std::string& scheme);
/// Creates an OAuth20Credentials object from a HTTPRequest object.
///
/// Extracts bearer token from the Authorization header, which must
/// use the given authorization scheme.
///
/// Throws a NotAuthenticatedException if the request does
/// not contain a bearer token in the Authorization header.
~OAuth20Credentials();
/// Destroys the HTTPCredentials.
void setBearerToken(const std::string& bearerToken);
/// Sets the bearer token.
const std::string& getBearerToken() const;
/// Returns the bearer token.
void setScheme(const std::string& scheme);
/// Sets the Authorization header scheme.
const std::string& getScheme() const;
/// Returns the Authorization header scheme.
void authenticate(HTTPRequest& request);
/// Adds an Authorization header containing the bearer token to
/// the HTTPRequest.
static const std::string SCHEME;
protected:
void extractBearerToken(const HTTPRequest& request);
/// Extracts the bearer token from the HTTPRequest.
private:
OAuth20Credentials(const OAuth20Credentials&);
OAuth20Credentials& operator = (const OAuth20Credentials&);
std::string _bearerToken;
std::string _scheme;
};
//
// inlines
//
inline const std::string& OAuth20Credentials::getBearerToken() const
{
return _bearerToken;
}
inline const std::string& OAuth20Credentials::getScheme() const
{
return _scheme;
}
} } // namespace Poco::Net
#endif // Net_OAuth20Credentials_INCLUDED

View File

@@ -16,7 +16,6 @@
#include "Poco/Net/OAuth10Credentials.h" #include "Poco/Net/OAuth10Credentials.h"
#include "Poco/Net/HTTPRequest.h" #include "Poco/Net/HTTPRequest.h"
#include "Poco/Net/HTTPResponse.h"
#include "Poco/Net/HTMLForm.h" #include "Poco/Net/HTMLForm.h"
#include "Poco/Net/NetException.h" #include "Poco/Net/NetException.h"
#include "Poco/Net/HTTPAuthenticationParams.h" #include "Poco/Net/HTTPAuthenticationParams.h"
@@ -28,6 +27,7 @@
#include "Poco/NumberParser.h" #include "Poco/NumberParser.h"
#include "Poco/NumberFormatter.h" #include "Poco/NumberFormatter.h"
#include "Poco/Format.h" #include "Poco/Format.h"
#include "Poco/String.h"
#include <map> #include <map>
#include <sstream> #include <sstream>
@@ -36,6 +36,9 @@ namespace Poco {
namespace Net { namespace Net {
const std::string OAuth10Credentials::SCHEME = "OAuth";
OAuth10Credentials::OAuth10Credentials() OAuth10Credentials::OAuth10Credentials()
{ {
} }
@@ -64,7 +67,7 @@ OAuth10Credentials::OAuth10Credentials(const Poco::Net::HTTPRequest& request)
std::string authScheme; std::string authScheme;
std::string authParams; std::string authParams;
request.getCredentials(authScheme, authParams); request.getCredentials(authScheme, authParams);
if (authScheme == "OAuth") if (icompare(authScheme, SCHEME) == 0)
{ {
HTTPAuthenticationParams params(authParams); HTTPAuthenticationParams params(authParams);
std::string consumerKey = params.get("oauth_consumer_key", ""); std::string consumerKey = params.get("oauth_consumer_key", "");
@@ -158,7 +161,7 @@ bool OAuth10Credentials::verify(const HTTPRequest& request, const Poco::URI& uri
std::string authScheme; std::string authScheme;
std::string authParams; std::string authParams;
request.getCredentials(authScheme, authParams); request.getCredentials(authScheme, authParams);
if (authScheme == "OAuth") if (icompare(authScheme, SCHEME) == 0)
{ {
HTTPAuthenticationParams oauthParams(authParams); HTTPAuthenticationParams oauthParams(authParams);
@@ -190,13 +193,13 @@ bool OAuth10Credentials::verify(const HTTPRequest& request, const Poco::URI& uri
URI::decode(signatureEnc, signature); URI::decode(signatureEnc, signature);
std::string refSignature; std::string refSignature;
if (method == "PLAINTEXT") if (icompare(method, "PLAINTEXT") == 0)
{ {
refSignature = percentEncode(_consumerSecret); refSignature = percentEncode(_consumerSecret);
refSignature += '&'; refSignature += '&';
refSignature += percentEncode(_tokenSecret); refSignature += percentEncode(_tokenSecret);
} }
else if (method == "HMAC-SHA1") else if (icompare(method, "HMAC-SHA1") == 0)
{ {
URI uriWithoutQuery(uri); URI uriWithoutQuery(uri);
uriWithoutQuery.setQuery(""); uriWithoutQuery.setQuery("");
@@ -226,7 +229,7 @@ void OAuth10Credentials::signPlaintext(Poco::Net::HTTPRequest& request) const
signature += '&'; signature += '&';
signature += percentEncode(_tokenSecret); signature += percentEncode(_tokenSecret);
std::string authorization("OAuth"); std::string authorization(SCHEME);
if (!_realm.empty()) if (!_realm.empty())
{ {
Poco::format(authorization, " realm=\"%s\",", _realm); Poco::format(authorization, " realm=\"%s\",", _realm);
@@ -244,7 +247,7 @@ void OAuth10Credentials::signPlaintext(Poco::Net::HTTPRequest& request) const
} }
authorization += ", oauth_version=\"1.0\""; authorization += ", oauth_version=\"1.0\"";
request.set("Authorization", authorization); request.set(HTTPRequest::AUTHORIZATION, authorization);
} }
@@ -262,7 +265,7 @@ void OAuth10Credentials::signHMACSHA1(Poco::Net::HTTPRequest& request, const std
} }
std::string signature(createSignature(request, uri, params, nonce, timestamp)); std::string signature(createSignature(request, uri, params, nonce, timestamp));
std::string authorization("OAuth"); std::string authorization(SCHEME);
if (!_realm.empty()) if (!_realm.empty())
{ {
Poco::format(authorization, " realm=\"%s\",", _realm); Poco::format(authorization, " realm=\"%s\",", _realm);
@@ -282,7 +285,7 @@ void OAuth10Credentials::signHMACSHA1(Poco::Net::HTTPRequest& request, const std
} }
authorization += ", oauth_version=\"1.0\""; authorization += ", oauth_version=\"1.0\"";
request.set("Authorization", authorization); request.set(HTTPRequest::AUTHORIZATION, authorization);
} }

View File

@@ -0,0 +1,107 @@
//
// OAuth20Credentials.cpp
//
// $Id$
//
// Library: Net
// Package: OAuth
// Module: OAuth20Credentials
//
// Copyright (c) 2014, Applied Informatics Software Engineering GmbH.
// and Contributors.
//
// SPDX-License-Identifier: BSL-1.0
//
#include "Poco/Net/OAuth20Credentials.h"
#include "Poco/Net/HTTPRequest.h"
#include "Poco/Net/NetException.h"
#include "Poco/String.h"
namespace Poco {
namespace Net {
const std::string OAuth20Credentials::SCHEME = "Bearer";
OAuth20Credentials::OAuth20Credentials():
_scheme(SCHEME)
{
}
OAuth20Credentials::OAuth20Credentials(const std::string& bearerToken):
_bearerToken(bearerToken),
_scheme(SCHEME)
{
}
OAuth20Credentials::OAuth20Credentials(const std::string& bearerToken, const std::string& scheme):
_bearerToken(bearerToken),
_scheme(scheme)
{
}
OAuth20Credentials::OAuth20Credentials(const HTTPRequest& request):
_scheme(SCHEME)
{
extractBearerToken(request);
}
OAuth20Credentials::OAuth20Credentials(const HTTPRequest& request, const std::string& scheme):
_scheme(scheme)
{
extractBearerToken(request);
}
OAuth20Credentials::~OAuth20Credentials()
{
}
void OAuth20Credentials::setBearerToken(const std::string& bearerToken)
{
_bearerToken = bearerToken;
}
void OAuth20Credentials::setScheme(const std::string& scheme)
{
_scheme = scheme;
}
void OAuth20Credentials::authenticate(HTTPRequest& request)
{
std::string auth(_scheme);
auth += ' ';
auth += _bearerToken;
request.set(HTTPRequest::AUTHORIZATION, auth);
}
void OAuth20Credentials::extractBearerToken(const HTTPRequest& request)
{
if (request.hasCredentials())
{
std::string authScheme;
std::string authInfo;
request.getCredentials(authScheme, authInfo);
if (icompare(authScheme, _scheme) == 0)
{
_bearerToken = authInfo;
}
else throw NotAuthenticatedException("No bearer token in Authorization header", authScheme);
}
else throw NotAuthenticatedException("No Authorization header found");
}
} } // namespace Poco::Net

View File

@@ -28,7 +28,7 @@ objects = \
NTPClientTest NTPClientTestSuite \ NTPClientTest NTPClientTestSuite \
WebSocketTest WebSocketTestSuite \ WebSocketTest WebSocketTestSuite \
SyslogTest \ SyslogTest \
OAuth10CredentialsTest OAuthTestSuite OAuth10CredentialsTest OAuth20CredentialsTest OAuthTestSuite
target = testrunner target = testrunner
target_version = 1 target_version = 1

View File

@@ -0,0 +1,109 @@
//
// OAuth20CredentialsTest.cpp
//
// $Id$
//
// Copyright (c) 2014, Applied Informatics Software Engineering GmbH.
// and Contributors.
//
// SPDX-License-Identifier: BSL-1.0
//
#include "OAuth20CredentialsTest.h"
#include "CppUnit/TestCaller.h"
#include "CppUnit/TestSuite.h"
#include "Poco/Net/HTTPRequest.h"
#include "Poco/Net/OAuth20Credentials.h"
#include "Poco/Net/NetException.h"
using Poco::Net::HTTPRequest;
using Poco::Net::OAuth20Credentials;
using Poco::Net::NotAuthenticatedException;
OAuth20CredentialsTest::OAuth20CredentialsTest(const std::string& name): CppUnit::TestCase(name)
{
}
OAuth20CredentialsTest::~OAuth20CredentialsTest()
{
}
void OAuth20CredentialsTest::testAuthorize()
{
OAuth20Credentials creds("s3cr3tt0k3n");
HTTPRequest request(HTTPRequest::HTTP_GET, "/");
creds.authenticate(request);
std::string auth = request.get("Authorization");
assert (auth == "Bearer s3cr3tt0k3n");
}
void OAuth20CredentialsTest::testAuthorizeCustomScheme()
{
OAuth20Credentials creds("s3cr3tt0k3n", "token");
HTTPRequest request(HTTPRequest::HTTP_GET, "/");
creds.authenticate(request);
std::string auth = request.get("Authorization");
assert (auth == "token s3cr3tt0k3n");
}
void OAuth20CredentialsTest::testExtract()
{
HTTPRequest request(HTTPRequest::HTTP_GET, "/");
request.set("Authorization", "Bearer s3cr3tt0k3n");
OAuth20Credentials creds(request);
assert (creds.getBearerToken() == "s3cr3tt0k3n");
}
void OAuth20CredentialsTest::testExtractCustomScheme()
{
HTTPRequest request(HTTPRequest::HTTP_GET, "/");
request.set("Authorization", "token s3cr3tt0k3n");
OAuth20Credentials creds(request, "token");
assert (creds.getBearerToken() == "s3cr3tt0k3n");
}
void OAuth20CredentialsTest::testExtractNoCreds()
{
HTTPRequest request(HTTPRequest::HTTP_GET, "/");
try
{
OAuth20Credentials creds(request);
fail("no credentials - must throw");
}
catch (NotAuthenticatedException&)
{
}
}
void OAuth20CredentialsTest::setUp()
{
}
void OAuth20CredentialsTest::tearDown()
{
}
CppUnit::Test* OAuth20CredentialsTest::suite()
{
CppUnit::TestSuite* pSuite = new CppUnit::TestSuite("OAuth20CredentialsTest");
CppUnit_addTest(pSuite, OAuth20CredentialsTest, testAuthorize);
CppUnit_addTest(pSuite, OAuth20CredentialsTest, testAuthorizeCustomScheme);
CppUnit_addTest(pSuite, OAuth20CredentialsTest, testExtract);
CppUnit_addTest(pSuite, OAuth20CredentialsTest, testExtractCustomScheme);
CppUnit_addTest(pSuite, OAuth20CredentialsTest, testExtractNoCreds);
return pSuite;
}

View File

@@ -0,0 +1,44 @@
//
// OAuth20CredentialsTest.h
//
// $Id$
//
// Definition of the OAuth20CredentialsTest class.
//
// Copyright (c) 2014, Applied Informatics Software Engineering GmbH.
// and Contributors.
//
// SPDX-License-Identifier: BSL-1.0
//
#ifndef OAuth20CredentialsTest_INCLUDED
#define OAuth20CredentialsTest_INCLUDED
#include "Poco/Net/Net.h"
#include "CppUnit/TestCase.h"
class OAuth20CredentialsTest: public CppUnit::TestCase
{
public:
OAuth20CredentialsTest(const std::string& name);
~OAuth20CredentialsTest();
void testAuthorize();
void testAuthorizeCustomScheme();
void testExtract();
void testExtractCustomScheme();
void testExtractNoCreds();
void setUp();
void tearDown();
static CppUnit::Test* suite();
private:
};
#endif // OAuth20CredentialsTest_INCLUDED

View File

@@ -12,6 +12,7 @@
#include "OAuthTestSuite.h" #include "OAuthTestSuite.h"
#include "OAuth10CredentialsTest.h" #include "OAuth10CredentialsTest.h"
#include "OAuth20CredentialsTest.h"
CppUnit::Test* OAuthTestSuite::suite() CppUnit::Test* OAuthTestSuite::suite()
@@ -19,6 +20,7 @@ CppUnit::Test* OAuthTestSuite::suite()
CppUnit::TestSuite* pSuite = new CppUnit::TestSuite("OAuthTestSuite"); CppUnit::TestSuite* pSuite = new CppUnit::TestSuite("OAuthTestSuite");
pSuite->addTest(OAuth10CredentialsTest::suite()); pSuite->addTest(OAuth10CredentialsTest::suite());
pSuite->addTest(OAuth20CredentialsTest::suite());
return pSuite; return pSuite;
} }