Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
81 changes: 14 additions & 67 deletions olp-cpp-sdk-authentication/src/AuthenticationClientImpl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,6 @@
#include <boost/uuid/uuid_io.hpp>
#include "AuthenticationClientUtils.h"
#include "Constants.h"
#include "Crypto.h"
#include "SignInResultImpl.h"
#include "SignInUserResultImpl.h"
#include "SignOutResultImpl.h"
Expand All @@ -43,31 +42,14 @@
#include "olp/core/http/NetworkUtils.h"
#include "olp/core/logging/Log.h"
#include "olp/core/thread/TaskScheduler.h"
#include "olp/core/utils/Base64.h"
#include "olp/core/utils/Url.h"

namespace {
namespace auth = olp::authentication;
namespace client = olp::client;

using olp::authentication::Constants;

// Helper characters
constexpr auto kParamAdd = "&";
constexpr auto kParamComma = ",";
constexpr auto kParamEquals = "=";
constexpr auto kParamQuote = "\"";
constexpr auto kLineFeed = '\n';

// Tags
constexpr auto kApplicationJson = "application/json";
const std::string kOauthPost = "POST";
const std::string kOauthConsumerKey = "oauth_consumer_key";
const std::string kOauthNonce = "oauth_nonce";
const std::string kOauthSignature = "oauth_signature";
const std::string kOauthTimestamp = "oauth_timestamp";
const std::string kOauthVersion = "oauth_version";
const std::string kOauthSignatureMethod = "oauth_signature_method";
const std::string kOauthEndpoint = "/oauth2/token";
const std::string kSignoutEndpoint = "/logout";
const std::string kTermsEndpoint = "/terms";
Expand Down Expand Up @@ -106,8 +88,6 @@ constexpr auto kResource = "resource";
constexpr auto kDiagnostics = "diagnostics";
constexpr auto kOperator = "operator";
// Values
constexpr auto kVersion = "1.0";
constexpr auto kHmac = "HMAC-SHA256";
constexpr auto kErrorWrongTimestamp = 401204;
constexpr auto kLogTag = "AuthenticationClient";

Expand Down Expand Up @@ -135,9 +115,11 @@ olp::client::HttpResponse AuthenticationClientImpl::CallAuth(
const SignInProperties& properties, std::time_t timestamp) {
const auto url = settings_.token_endpoint_url + kOauthEndpoint;

auto auth_header =
GenerateAuthorizationHeader(credentials, url, timestamp, GenerateUid());

client::OlpClient::ParametersType headers = {
{http::kAuthorizationHeader,
GenerateHeader(credentials, url, timestamp)}};
{http::kAuthorizationHeader, std::move(auth_header)}};
if (context.IsCancelled()) {
return {static_cast<int>(olp::http::ErrorCode::CANCELLED_ERROR),
"Cancelled"};
Expand Down Expand Up @@ -354,8 +336,11 @@ client::CancellationToken AuthenticationClientImpl::HandleUserRequest(
network_settings.WithProxySettings(settings_.network_proxy_settings.get());
}
request.WithVerb(http::NetworkRequest::HttpVerb::POST);
request.WithHeader(http::kAuthorizationHeader,
GenerateHeader(credentials, url));

auto auth_header = GenerateAuthorizationHeader(
credentials, url, std::time(nullptr), GenerateUid());

request.WithHeader(http::kAuthorizationHeader, std::move(auth_header));
request.WithHeader(http::kContentTypeHeader, kApplicationJson);
request.WithHeader(http::kUserAgentHeader, http::kOlpSdkUserAgent);
request.WithSettings(std::move(network_settings));
Expand Down Expand Up @@ -465,8 +450,11 @@ client::CancellationToken AuthenticationClientImpl::SignUpHereUser(
network_settings.WithProxySettings(settings_.network_proxy_settings.get());
}
request.WithVerb(http::NetworkRequest::HttpVerb::POST);
request.WithHeader(http::kAuthorizationHeader,
GenerateHeader(credentials, url));

auto auth_header = GenerateAuthorizationHeader(
credentials, url, std::time(nullptr), GenerateUid());

request.WithHeader(http::kAuthorizationHeader, std::move(auth_header));
request.WithHeader(http::kContentTypeHeader, kApplicationJson);
request.WithHeader(http::kUserAgentHeader, http::kOlpSdkUserAgent);
request.WithSettings(std::move(network_settings));
Expand Down Expand Up @@ -695,47 +683,6 @@ client::CancellationToken AuthenticationClientImpl::Authorize(
std::move(callback));
}

std::string AuthenticationClientImpl::Base64Encode(
const std::vector<uint8_t>& vector) {
std::string ret = olp::utils::Base64Encode(vector);
// Base64 encode sometimes return multiline with garbage at the end
if (!ret.empty()) {
auto loc = ret.find(kLineFeed);
if (loc != std::string::npos) ret = ret.substr(0, loc);
}
return ret;
}

std::string AuthenticationClientImpl::GenerateHeader(
const AuthenticationCredentials& credentials, const std::string& url,
const time_t& timestamp) {
std::string uid = GenerateUid();
const std::string currentTime = std::to_string(timestamp);
const std::string encodedUri = utils::Url::Encode(url);
const std::string encodedQuery = utils::Url::Encode(
kOauthConsumerKey + kParamEquals + credentials.GetKey() + kParamAdd +
kOauthNonce + kParamEquals + uid + kParamAdd + kOauthSignatureMethod +
kParamEquals + kHmac + kParamAdd + kOauthTimestamp + kParamEquals +
currentTime + kParamAdd + kOauthVersion + kParamEquals + kVersion);
const std::string signatureBase =
kOauthPost + kParamAdd + encodedUri + kParamAdd + encodedQuery;
const std::string encodeKey = credentials.GetSecret() + kParamAdd;
auto hmacResult = Crypto::hmac_sha256(encodeKey, signatureBase);
auto signature = Base64Encode(hmacResult);
std::string authorization =
"OAuth " + kOauthConsumerKey + kParamEquals + kParamQuote +
utils::Url::Encode(credentials.GetKey()) + kParamQuote + kParamComma +
kOauthNonce + kParamEquals + kParamQuote + utils::Url::Encode(uid) +
kParamQuote + kParamComma + kOauthSignatureMethod + kParamEquals +
kParamQuote + kHmac + kParamQuote + kParamComma + kOauthTimestamp +
kParamEquals + kParamQuote + utils::Url::Encode(currentTime) +
kParamQuote + kParamComma + kOauthVersion + kParamEquals + kParamQuote +
kVersion + kParamQuote + kParamComma + kOauthSignature + kParamEquals +
kParamQuote + utils::Url::Encode(signature) + kParamQuote;

return authorization;
}

std::string AuthenticationClientImpl::GenerateBearerHeader(
const std::string& bearer_token) {
std::string authorization = http::kBearer + std::string(" ");
Expand Down
6 changes: 0 additions & 6 deletions olp-cpp-sdk-authentication/src/AuthenticationClientImpl.h
Original file line number Diff line number Diff line change
Expand Up @@ -126,12 +126,6 @@ class AuthenticationClientImpl final {

static TimeResponse ParseTimeResponse(std::stringstream& payload);

std::string Base64Encode(const std::vector<uint8_t>& vector);

std::string GenerateHeader(const AuthenticationCredentials& credentials,
const std::string& url,
const time_t& timestamp = std::time(nullptr));

std::string GenerateBearerHeader(const std::string& bearer_token);

client::OlpClient::RequestBodyType GenerateClientBody(
Expand Down
113 changes: 94 additions & 19 deletions olp-cpp-sdk-authentication/src/AuthenticationClientUtils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,21 +19,54 @@

#include "AuthenticationClientUtils.h"

#include <chrono>
#include <iomanip>
#include <sstream>

#include <rapidjson/document.h>
#include <rapidjson/istreamwrapper.h>
#include <rapidjson/stringbuffer.h>
#include <rapidjson/writer.h>

#include <chrono>
#include <iomanip>
#include <sstream>

#include "Constants.h"
#include "Crypto.h"
#include "olp/core/http/NetworkUtils.h"
#include "olp/core/utils/Base64.h"
#include "olp/core/utils/Url.h"

namespace olp {
namespace authentication {
namespace auth = olp::authentication;

namespace {
// Helper characters
constexpr auto kParamAdd = "&";
constexpr auto kParamComma = ",";
constexpr auto kParamEquals = "=";
constexpr auto kParamQuote = "\"";
constexpr auto kLineFeed = '\n';

constexpr auto kOauthPost = "POST";
constexpr auto kOauthVersion = "oauth_version";
constexpr auto kOauthConsumerKey = "oauth_consumer_key";
constexpr auto kOauthNonce = "oauth_nonce";
constexpr auto kOauthSignature = "oauth_signature";
constexpr auto kOauthTimestamp = "oauth_timestamp";
constexpr auto kOauthSignatureMethod = "oauth_signature_method";
constexpr auto kVersion = "1.0";
constexpr auto kHmac = "HMAC-SHA256";

std::string Base64Encode(const std::vector<uint8_t>& vector) {
std::string ret = olp::utils::Base64Encode(vector);
// Base64 encode sometimes return multiline with garbage at the end
if (!ret.empty()) {
auto loc = ret.find(kLineFeed);
if (loc != std::string::npos) ret = ret.substr(0, loc);
}
return ret;
}

} // namespace

namespace client = olp::client;

constexpr auto kDate = "date";
Expand Down Expand Up @@ -75,9 +108,8 @@ void ExecuteOrSchedule(
task_scheduler->ScheduleTask(std::move(func));
}

auth::IntrospectAppResult GetIntrospectAppResult(
const rapidjson::Document& doc) {
auth::IntrospectAppResult result;
IntrospectAppResult GetIntrospectAppResult(const rapidjson::Document& doc) {
IntrospectAppResult result;
if (doc.HasMember(Constants::CLIENT_ID)) {
result.SetClientId(doc[Constants::CLIENT_ID].GetString());
}
Expand Down Expand Up @@ -161,27 +193,27 @@ auth::IntrospectAppResult GetIntrospectAppResult(
return result;
}

auth::DecisionType GetPermission(const std::string& str) {
return (str.compare("allow") == 0) ? auth::DecisionType::kAllow
: auth::DecisionType::kDeny;
DecisionType GetPermission(const std::string& str) {
return (str.compare("allow") == 0) ? DecisionType::kAllow
: DecisionType::kDeny;
}

std::vector<auth::ActionResult> GetDiagnostics(rapidjson::Document& doc) {
std::vector<auth::ActionResult> results;
std::vector<ActionResult> GetDiagnostics(rapidjson::Document& doc) {
std::vector<ActionResult> results;
const auto& array = doc[Constants::DIAGNOSTICS].GetArray();
for (auto& element : array) {
auth::ActionResult action;
ActionResult action;
if (element.HasMember(Constants::DECISION)) {
action.SetDecision(
GetPermission(element[Constants::DECISION].GetString()));
// get permissions if avialible
if (element.HasMember(Constants::PERMISSIONS) &&
element[Constants::PERMISSIONS].IsArray()) {
std::vector<auth::ActionResult::Permissions> permissions;
std::vector<ActionResult::Permissions> permissions;
const auto& permissions_array =
element[Constants::PERMISSIONS].GetArray();
for (auto& permission_element : permissions_array) {
auth::ActionResult::Permissions permission;
ActionResult::Permissions permission;
if (permission_element.HasMember(Constants::ACTION)) {
permission.first =
permission_element[Constants::ACTION].GetString();
Expand All @@ -201,8 +233,8 @@ std::vector<auth::ActionResult> GetDiagnostics(rapidjson::Document& doc) {
return results;
}

auth::AuthorizeResult GetAuthorizeResult(rapidjson::Document& doc) {
auth::AuthorizeResult result;
AuthorizeResult GetAuthorizeResult(rapidjson::Document& doc) {
AuthorizeResult result;

if (doc.HasMember(Constants::IDENTITY)) {
auto uris = doc[Constants::IDENTITY].GetObject();
Expand All @@ -227,7 +259,7 @@ auth::AuthorizeResult GetAuthorizeResult(rapidjson::Document& doc) {
}

client::OlpClient CreateOlpClient(
const auth::AuthenticationSettings& auth_settings,
const AuthenticationSettings& auth_settings,
boost::optional<client::AuthenticationSettings> authentication_settings) {
client::OlpClientSettings settings;
settings.network_request_handler = auth_settings.network_request_handler;
Expand All @@ -242,5 +274,48 @@ client::OlpClient CreateOlpClient(
return client;
}

std::string GenerateAuthorizationHeader(
const AuthenticationCredentials& credentials, const std::string& url,
time_t timestamp, std::string nonce) {
const std::string timestamp_str = std::to_string(timestamp);

std::stringstream stream;

stream << kOauthConsumerKey << kParamEquals << credentials.GetKey()
<< kParamAdd << kOauthNonce << kParamEquals << nonce << kParamAdd
<< kOauthSignatureMethod << kParamEquals << kHmac << kParamAdd
<< kOauthTimestamp << kParamEquals << timestamp_str << kParamAdd
<< kOauthVersion << kParamEquals << kVersion;

const auto encoded_query = utils::Url::Encode(stream.str());

stream.clear();

stream << kOauthPost << kParamAdd << utils::Url::Encode(url) << kParamAdd
<< encoded_query;

const auto signature_base = stream.str();

stream.clear();

const std::string encode_key = credentials.GetSecret() + kParamAdd;
auto hmac_result = Crypto::hmac_sha256(encode_key, signature_base);
auto signature = Base64Encode(hmac_result);

stream << "OAuth " << kOauthConsumerKey << kParamEquals << kParamQuote
<< utils::Url::Encode(credentials.GetKey()) << kParamQuote
<< kParamComma << kOauthNonce << kParamEquals << kParamQuote
<< utils::Url::Encode(nonce) << kParamQuote << kParamComma
<< kOauthSignatureMethod << kParamEquals << kParamQuote << kHmac
<< kParamQuote << kParamComma << kOauthTimestamp << kParamEquals
<< kParamQuote << utils::Url::Encode(timestamp_str) << kParamQuote
<< kParamComma << kOauthVersion << kParamEquals << kParamQuote
<< kVersion << kParamQuote << kParamComma << kOauthSignature
<< kParamEquals << kParamQuote << utils::Url::Encode(signature)
<< kParamQuote;

return stream.str();
}

} // namespace authentication
} // namespace olp
15 changes: 15 additions & 0 deletions olp-cpp-sdk-authentication/src/AuthenticationClientUtils.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@

#include <rapidjson/document.h>

#include "olp/authentication/AuthenticationCredentials.h"
#include "olp/authentication/AuthenticationSettings.h"
#include "olp/authentication/AuthorizeResult.h"
#include "olp/authentication/ErrorResponse.h"
Expand Down Expand Up @@ -129,5 +130,19 @@ client::OlpClient CreateOlpClient(
const AuthenticationSettings& auth_settings,
boost::optional<client::AuthenticationSettings> authentication_settings);

/*
* @brief Generate authorization header.
*
* @param credentials Client credentials.
* @param url Authorization endpoint URL.
* @param timestamp Current time.
* @param nonce A unique value, must be used once. (Refer to OAuth docs).
*
* @return The authorization header string.
*/
std::string GenerateAuthorizationHeader(
const AuthenticationCredentials& credentials, const std::string& url,
time_t timestamp, std::string nonce);

} // namespace authentication
} // namespace olp
21 changes: 19 additions & 2 deletions olp-cpp-sdk-authentication/tests/AuthenticationClientTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,10 +28,27 @@ namespace {
constexpr auto kTime = "Fri, 29 May 2020 11:07:45 GMT";
} // namespace

namespace auth = olp::authentication;

TEST(AuthenticationClientTest, TimeParsing) {
{
SCOPED_TRACE("Parse time");

EXPECT_EQ(olp::authentication::ParseTime(kTime), 1590750465);
EXPECT_EQ(auth::ParseTime(kTime), 1590750465);
}
}

TEST(AuthenticationClientTest, GenerateAuthorizationHeader) {
auth::AuthenticationCredentials credentials("key", "secret");
const auto url = "https://auth.server.com";
auto sig = auth::GenerateAuthorizationHeader(credentials, url, 0, "unique");
auto expected_sig =
"oauth_consumer_key=key&oauth_nonce=unique&oauth_signature_method=HMAC-"
"SHA256&oauth_timestamp=0&oauth_version=1.0POST&https%3A%2F%2Fauth."
"server.com&oauth_consumer_key%3Dkey%26oauth_nonce%3Dunique%26oauth_"
"signature_method%3DHMAC-SHA256%26oauth_timestamp%3D0%26oauth_version%"
"3D1.0OAuth "
"oauth_consumer_key=\"key\",oauth_nonce=\"unique\",oauth_signature_"
"method=\"HMAC-SHA256\",oauth_timestamp=\"0\",oauth_version=\"1.0\","
"oauth_signature=\"ncwRtcqRSM04FIFch8Ay4l7bRmp96lifuHEops4AqEw%3D\"";
EXPECT_EQ(sig, expected_sig);
}