Skip to content

Commit 7563ed4

Browse files
Move the authorization header function to utils (#899)
This is needed to enable testing and enabled new code to reuse it. Adapt function to coding style, switch from string concatenation to reusable string stream. Remove a needless auth namespace. Resolves: OLPEDGE-2030 Signed-off-by: Mykhailo Kuchma <ext-mykhailo.kuchma@here.com>
1 parent b3a7ec8 commit 7563ed4

File tree

5 files changed

+142
-94
lines changed

5 files changed

+142
-94
lines changed

olp-cpp-sdk-authentication/src/AuthenticationClientImpl.cpp

Lines changed: 14 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,6 @@
3232
#include <boost/uuid/uuid_io.hpp>
3333
#include "AuthenticationClientUtils.h"
3434
#include "Constants.h"
35-
#include "Crypto.h"
3635
#include "SignInResultImpl.h"
3736
#include "SignInUserResultImpl.h"
3837
#include "SignOutResultImpl.h"
@@ -43,31 +42,14 @@
4342
#include "olp/core/http/NetworkUtils.h"
4443
#include "olp/core/logging/Log.h"
4544
#include "olp/core/thread/TaskScheduler.h"
46-
#include "olp/core/utils/Base64.h"
47-
#include "olp/core/utils/Url.h"
4845

4946
namespace {
50-
namespace auth = olp::authentication;
5147
namespace client = olp::client;
5248

5349
using olp::authentication::Constants;
5450

55-
// Helper characters
56-
constexpr auto kParamAdd = "&";
57-
constexpr auto kParamComma = ",";
58-
constexpr auto kParamEquals = "=";
59-
constexpr auto kParamQuote = "\"";
60-
constexpr auto kLineFeed = '\n';
61-
6251
// Tags
6352
constexpr auto kApplicationJson = "application/json";
64-
const std::string kOauthPost = "POST";
65-
const std::string kOauthConsumerKey = "oauth_consumer_key";
66-
const std::string kOauthNonce = "oauth_nonce";
67-
const std::string kOauthSignature = "oauth_signature";
68-
const std::string kOauthTimestamp = "oauth_timestamp";
69-
const std::string kOauthVersion = "oauth_version";
70-
const std::string kOauthSignatureMethod = "oauth_signature_method";
7153
const std::string kOauthEndpoint = "/oauth2/token";
7254
const std::string kSignoutEndpoint = "/logout";
7355
const std::string kTermsEndpoint = "/terms";
@@ -106,8 +88,6 @@ constexpr auto kResource = "resource";
10688
constexpr auto kDiagnostics = "diagnostics";
10789
constexpr auto kOperator = "operator";
10890
// Values
109-
constexpr auto kVersion = "1.0";
110-
constexpr auto kHmac = "HMAC-SHA256";
11191
constexpr auto kErrorWrongTimestamp = 401204;
11292
constexpr auto kLogTag = "AuthenticationClient";
11393

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

118+
auto auth_header =
119+
GenerateAuthorizationHeader(credentials, url, timestamp, GenerateUid());
120+
138121
client::OlpClient::ParametersType headers = {
139-
{http::kAuthorizationHeader,
140-
GenerateHeader(credentials, url, timestamp)}};
122+
{http::kAuthorizationHeader, std::move(auth_header)}};
141123
if (context.IsCancelled()) {
142124
return {static_cast<int>(olp::http::ErrorCode::CANCELLED_ERROR),
143125
"Cancelled"};
@@ -354,8 +336,11 @@ client::CancellationToken AuthenticationClientImpl::HandleUserRequest(
354336
network_settings.WithProxySettings(settings_.network_proxy_settings.get());
355337
}
356338
request.WithVerb(http::NetworkRequest::HttpVerb::POST);
357-
request.WithHeader(http::kAuthorizationHeader,
358-
GenerateHeader(credentials, url));
339+
340+
auto auth_header = GenerateAuthorizationHeader(
341+
credentials, url, std::time(nullptr), GenerateUid());
342+
343+
request.WithHeader(http::kAuthorizationHeader, std::move(auth_header));
359344
request.WithHeader(http::kContentTypeHeader, kApplicationJson);
360345
request.WithHeader(http::kUserAgentHeader, http::kOlpSdkUserAgent);
361346
request.WithSettings(std::move(network_settings));
@@ -465,8 +450,11 @@ client::CancellationToken AuthenticationClientImpl::SignUpHereUser(
465450
network_settings.WithProxySettings(settings_.network_proxy_settings.get());
466451
}
467452
request.WithVerb(http::NetworkRequest::HttpVerb::POST);
468-
request.WithHeader(http::kAuthorizationHeader,
469-
GenerateHeader(credentials, url));
453+
454+
auto auth_header = GenerateAuthorizationHeader(
455+
credentials, url, std::time(nullptr), GenerateUid());
456+
457+
request.WithHeader(http::kAuthorizationHeader, std::move(auth_header));
470458
request.WithHeader(http::kContentTypeHeader, kApplicationJson);
471459
request.WithHeader(http::kUserAgentHeader, http::kOlpSdkUserAgent);
472460
request.WithSettings(std::move(network_settings));
@@ -695,47 +683,6 @@ client::CancellationToken AuthenticationClientImpl::Authorize(
695683
std::move(callback));
696684
}
697685

698-
std::string AuthenticationClientImpl::Base64Encode(
699-
const std::vector<uint8_t>& vector) {
700-
std::string ret = olp::utils::Base64Encode(vector);
701-
// Base64 encode sometimes return multiline with garbage at the end
702-
if (!ret.empty()) {
703-
auto loc = ret.find(kLineFeed);
704-
if (loc != std::string::npos) ret = ret.substr(0, loc);
705-
}
706-
return ret;
707-
}
708-
709-
std::string AuthenticationClientImpl::GenerateHeader(
710-
const AuthenticationCredentials& credentials, const std::string& url,
711-
const time_t& timestamp) {
712-
std::string uid = GenerateUid();
713-
const std::string currentTime = std::to_string(timestamp);
714-
const std::string encodedUri = utils::Url::Encode(url);
715-
const std::string encodedQuery = utils::Url::Encode(
716-
kOauthConsumerKey + kParamEquals + credentials.GetKey() + kParamAdd +
717-
kOauthNonce + kParamEquals + uid + kParamAdd + kOauthSignatureMethod +
718-
kParamEquals + kHmac + kParamAdd + kOauthTimestamp + kParamEquals +
719-
currentTime + kParamAdd + kOauthVersion + kParamEquals + kVersion);
720-
const std::string signatureBase =
721-
kOauthPost + kParamAdd + encodedUri + kParamAdd + encodedQuery;
722-
const std::string encodeKey = credentials.GetSecret() + kParamAdd;
723-
auto hmacResult = Crypto::hmac_sha256(encodeKey, signatureBase);
724-
auto signature = Base64Encode(hmacResult);
725-
std::string authorization =
726-
"OAuth " + kOauthConsumerKey + kParamEquals + kParamQuote +
727-
utils::Url::Encode(credentials.GetKey()) + kParamQuote + kParamComma +
728-
kOauthNonce + kParamEquals + kParamQuote + utils::Url::Encode(uid) +
729-
kParamQuote + kParamComma + kOauthSignatureMethod + kParamEquals +
730-
kParamQuote + kHmac + kParamQuote + kParamComma + kOauthTimestamp +
731-
kParamEquals + kParamQuote + utils::Url::Encode(currentTime) +
732-
kParamQuote + kParamComma + kOauthVersion + kParamEquals + kParamQuote +
733-
kVersion + kParamQuote + kParamComma + kOauthSignature + kParamEquals +
734-
kParamQuote + utils::Url::Encode(signature) + kParamQuote;
735-
736-
return authorization;
737-
}
738-
739686
std::string AuthenticationClientImpl::GenerateBearerHeader(
740687
const std::string& bearer_token) {
741688
std::string authorization = http::kBearer + std::string(" ");

olp-cpp-sdk-authentication/src/AuthenticationClientImpl.h

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -126,12 +126,6 @@ class AuthenticationClientImpl final {
126126

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

129-
std::string Base64Encode(const std::vector<uint8_t>& vector);
130-
131-
std::string GenerateHeader(const AuthenticationCredentials& credentials,
132-
const std::string& url,
133-
const time_t& timestamp = std::time(nullptr));
134-
135129
std::string GenerateBearerHeader(const std::string& bearer_token);
136130

137131
client::OlpClient::RequestBodyType GenerateClientBody(

olp-cpp-sdk-authentication/src/AuthenticationClientUtils.cpp

Lines changed: 94 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -19,21 +19,54 @@
1919

2020
#include "AuthenticationClientUtils.h"
2121

22+
#include <chrono>
23+
#include <iomanip>
24+
#include <sstream>
25+
2226
#include <rapidjson/document.h>
2327
#include <rapidjson/istreamwrapper.h>
2428
#include <rapidjson/stringbuffer.h>
2529
#include <rapidjson/writer.h>
2630

27-
#include <chrono>
28-
#include <iomanip>
29-
#include <sstream>
30-
3131
#include "Constants.h"
32+
#include "Crypto.h"
3233
#include "olp/core/http/NetworkUtils.h"
34+
#include "olp/core/utils/Base64.h"
35+
#include "olp/core/utils/Url.h"
3336

3437
namespace olp {
3538
namespace authentication {
36-
namespace auth = olp::authentication;
39+
40+
namespace {
41+
// Helper characters
42+
constexpr auto kParamAdd = "&";
43+
constexpr auto kParamComma = ",";
44+
constexpr auto kParamEquals = "=";
45+
constexpr auto kParamQuote = "\"";
46+
constexpr auto kLineFeed = '\n';
47+
48+
constexpr auto kOauthPost = "POST";
49+
constexpr auto kOauthVersion = "oauth_version";
50+
constexpr auto kOauthConsumerKey = "oauth_consumer_key";
51+
constexpr auto kOauthNonce = "oauth_nonce";
52+
constexpr auto kOauthSignature = "oauth_signature";
53+
constexpr auto kOauthTimestamp = "oauth_timestamp";
54+
constexpr auto kOauthSignatureMethod = "oauth_signature_method";
55+
constexpr auto kVersion = "1.0";
56+
constexpr auto kHmac = "HMAC-SHA256";
57+
58+
std::string Base64Encode(const std::vector<uint8_t>& vector) {
59+
std::string ret = olp::utils::Base64Encode(vector);
60+
// Base64 encode sometimes return multiline with garbage at the end
61+
if (!ret.empty()) {
62+
auto loc = ret.find(kLineFeed);
63+
if (loc != std::string::npos) ret = ret.substr(0, loc);
64+
}
65+
return ret;
66+
}
67+
68+
} // namespace
69+
3770
namespace client = olp::client;
3871

3972
constexpr auto kDate = "date";
@@ -75,9 +108,8 @@ void ExecuteOrSchedule(
75108
task_scheduler->ScheduleTask(std::move(func));
76109
}
77110

78-
auth::IntrospectAppResult GetIntrospectAppResult(
79-
const rapidjson::Document& doc) {
80-
auth::IntrospectAppResult result;
111+
IntrospectAppResult GetIntrospectAppResult(const rapidjson::Document& doc) {
112+
IntrospectAppResult result;
81113
if (doc.HasMember(Constants::CLIENT_ID)) {
82114
result.SetClientId(doc[Constants::CLIENT_ID].GetString());
83115
}
@@ -161,27 +193,27 @@ auth::IntrospectAppResult GetIntrospectAppResult(
161193
return result;
162194
}
163195

164-
auth::DecisionType GetPermission(const std::string& str) {
165-
return (str.compare("allow") == 0) ? auth::DecisionType::kAllow
166-
: auth::DecisionType::kDeny;
196+
DecisionType GetPermission(const std::string& str) {
197+
return (str.compare("allow") == 0) ? DecisionType::kAllow
198+
: DecisionType::kDeny;
167199
}
168200

169-
std::vector<auth::ActionResult> GetDiagnostics(rapidjson::Document& doc) {
170-
std::vector<auth::ActionResult> results;
201+
std::vector<ActionResult> GetDiagnostics(rapidjson::Document& doc) {
202+
std::vector<ActionResult> results;
171203
const auto& array = doc[Constants::DIAGNOSTICS].GetArray();
172204
for (auto& element : array) {
173-
auth::ActionResult action;
205+
ActionResult action;
174206
if (element.HasMember(Constants::DECISION)) {
175207
action.SetDecision(
176208
GetPermission(element[Constants::DECISION].GetString()));
177209
// get permissions if avialible
178210
if (element.HasMember(Constants::PERMISSIONS) &&
179211
element[Constants::PERMISSIONS].IsArray()) {
180-
std::vector<auth::ActionResult::Permissions> permissions;
212+
std::vector<ActionResult::Permissions> permissions;
181213
const auto& permissions_array =
182214
element[Constants::PERMISSIONS].GetArray();
183215
for (auto& permission_element : permissions_array) {
184-
auth::ActionResult::Permissions permission;
216+
ActionResult::Permissions permission;
185217
if (permission_element.HasMember(Constants::ACTION)) {
186218
permission.first =
187219
permission_element[Constants::ACTION].GetString();
@@ -201,8 +233,8 @@ std::vector<auth::ActionResult> GetDiagnostics(rapidjson::Document& doc) {
201233
return results;
202234
}
203235

204-
auth::AuthorizeResult GetAuthorizeResult(rapidjson::Document& doc) {
205-
auth::AuthorizeResult result;
236+
AuthorizeResult GetAuthorizeResult(rapidjson::Document& doc) {
237+
AuthorizeResult result;
206238

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

229261
client::OlpClient CreateOlpClient(
230-
const auth::AuthenticationSettings& auth_settings,
262+
const AuthenticationSettings& auth_settings,
231263
boost::optional<client::AuthenticationSettings> authentication_settings) {
232264
client::OlpClientSettings settings;
233265
settings.network_request_handler = auth_settings.network_request_handler;
@@ -242,5 +274,48 @@ client::OlpClient CreateOlpClient(
242274
return client;
243275
}
244276

277+
std::string GenerateAuthorizationHeader(
278+
const AuthenticationCredentials& credentials, const std::string& url,
279+
time_t timestamp, std::string nonce) {
280+
const std::string timestamp_str = std::to_string(timestamp);
281+
282+
std::stringstream stream;
283+
284+
stream << kOauthConsumerKey << kParamEquals << credentials.GetKey()
285+
<< kParamAdd << kOauthNonce << kParamEquals << nonce << kParamAdd
286+
<< kOauthSignatureMethod << kParamEquals << kHmac << kParamAdd
287+
<< kOauthTimestamp << kParamEquals << timestamp_str << kParamAdd
288+
<< kOauthVersion << kParamEquals << kVersion;
289+
290+
const auto encoded_query = utils::Url::Encode(stream.str());
291+
292+
stream.clear();
293+
294+
stream << kOauthPost << kParamAdd << utils::Url::Encode(url) << kParamAdd
295+
<< encoded_query;
296+
297+
const auto signature_base = stream.str();
298+
299+
stream.clear();
300+
301+
const std::string encode_key = credentials.GetSecret() + kParamAdd;
302+
auto hmac_result = Crypto::hmac_sha256(encode_key, signature_base);
303+
auto signature = Base64Encode(hmac_result);
304+
305+
stream << "OAuth " << kOauthConsumerKey << kParamEquals << kParamQuote
306+
<< utils::Url::Encode(credentials.GetKey()) << kParamQuote
307+
<< kParamComma << kOauthNonce << kParamEquals << kParamQuote
308+
<< utils::Url::Encode(nonce) << kParamQuote << kParamComma
309+
<< kOauthSignatureMethod << kParamEquals << kParamQuote << kHmac
310+
<< kParamQuote << kParamComma << kOauthTimestamp << kParamEquals
311+
<< kParamQuote << utils::Url::Encode(timestamp_str) << kParamQuote
312+
<< kParamComma << kOauthVersion << kParamEquals << kParamQuote
313+
<< kVersion << kParamQuote << kParamComma << kOauthSignature
314+
<< kParamEquals << kParamQuote << utils::Url::Encode(signature)
315+
<< kParamQuote;
316+
317+
return stream.str();
318+
}
319+
245320
} // namespace authentication
246321
} // namespace olp

olp-cpp-sdk-authentication/src/AuthenticationClientUtils.h

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525

2626
#include <rapidjson/document.h>
2727

28+
#include "olp/authentication/AuthenticationCredentials.h"
2829
#include "olp/authentication/AuthenticationSettings.h"
2930
#include "olp/authentication/AuthorizeResult.h"
3031
#include "olp/authentication/ErrorResponse.h"
@@ -129,5 +130,19 @@ client::OlpClient CreateOlpClient(
129130
const AuthenticationSettings& auth_settings,
130131
boost::optional<client::AuthenticationSettings> authentication_settings);
131132

133+
/*
134+
* @brief Generate authorization header.
135+
*
136+
* @param credentials Client credentials.
137+
* @param url Authorization endpoint URL.
138+
* @param timestamp Current time.
139+
* @param nonce A unique value, must be used once. (Refer to OAuth docs).
140+
*
141+
* @return The authorization header string.
142+
*/
143+
std::string GenerateAuthorizationHeader(
144+
const AuthenticationCredentials& credentials, const std::string& url,
145+
time_t timestamp, std::string nonce);
146+
132147
} // namespace authentication
133148
} // namespace olp

olp-cpp-sdk-authentication/tests/AuthenticationClientTest.cpp

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,10 +28,27 @@ namespace {
2828
constexpr auto kTime = "Fri, 29 May 2020 11:07:45 GMT";
2929
} // namespace
3030

31+
namespace auth = olp::authentication;
32+
3133
TEST(AuthenticationClientTest, TimeParsing) {
3234
{
3335
SCOPED_TRACE("Parse time");
34-
35-
EXPECT_EQ(olp::authentication::ParseTime(kTime), 1590750465);
36+
EXPECT_EQ(auth::ParseTime(kTime), 1590750465);
3637
}
3738
}
39+
40+
TEST(AuthenticationClientTest, GenerateAuthorizationHeader) {
41+
auth::AuthenticationCredentials credentials("key", "secret");
42+
const auto url = "https://auth.server.com";
43+
auto sig = auth::GenerateAuthorizationHeader(credentials, url, 0, "unique");
44+
auto expected_sig =
45+
"oauth_consumer_key=key&oauth_nonce=unique&oauth_signature_method=HMAC-"
46+
"SHA256&oauth_timestamp=0&oauth_version=1.0POST&https%3A%2F%2Fauth."
47+
"server.com&oauth_consumer_key%3Dkey%26oauth_nonce%3Dunique%26oauth_"
48+
"signature_method%3DHMAC-SHA256%26oauth_timestamp%3D0%26oauth_version%"
49+
"3D1.0OAuth "
50+
"oauth_consumer_key=\"key\",oauth_nonce=\"unique\",oauth_signature_"
51+
"method=\"HMAC-SHA256\",oauth_timestamp=\"0\",oauth_version=\"1.0\","
52+
"oauth_signature=\"ncwRtcqRSM04FIFch8Ay4l7bRmp96lifuHEops4AqEw%3D\"";
53+
EXPECT_EQ(sig, expected_sig);
54+
}

0 commit comments

Comments
 (0)