diff --git a/olp-cpp-sdk-authentication/CMakeLists.txt b/olp-cpp-sdk-authentication/CMakeLists.txt index b8d9cc787..64908df2e 100644 --- a/olp-cpp-sdk-authentication/CMakeLists.txt +++ b/olp-cpp-sdk-authentication/CMakeLists.txt @@ -18,6 +18,8 @@ project(olp-cpp-sdk-authentication VERSION 1.24.0) set(DESCRIPTION "C++ API library for accessing HERE Account authentication service") +find_package(Boost REQUIRED) + file(GLOB_RECURSE AUTHENTICATION_INC "include/*.h*") file(GLOB_RECURSE AUTHENTICATION_SRC "src/*.*") @@ -27,6 +29,7 @@ add_library(${PROJECT_NAME} target_include_directories(${PROJECT_NAME} PUBLIC $ + $ $) # Used also in the package config file @@ -37,8 +40,9 @@ target_link_libraries(${PROJECT_NAME} ${PROJECT_LIBS} ) -# On MINGW boost uses bcrypt library -if (MINGW) +# On MINGW and MSVC boost uses bcrypt library +# https://github.com/boostorg/uuid/issues/122 +if (MINGW OR MSVC) target_link_libraries(${PROJECT_NAME} PRIVATE bcrypt ) endif() @@ -49,6 +53,11 @@ if(BUILD_SHARED_LIBS) PUBLIC AUTHENTICATION_SHARED_LIBRARY) endif() +target_compile_definitions(${PROJECT_NAME} + PRIVATE + BOOST_ALL_NO_LIB + BOOST_JSON_NO_LIB) + # install component install (FILES ${AUTHENTICATION_INC} DESTINATION ${INCLUDE_DIRECTORY}/olp/authentication) diff --git a/olp-cpp-sdk-authentication/src/AuthenticationClientImpl.cpp b/olp-cpp-sdk-authentication/src/AuthenticationClientImpl.cpp index 567c1cde8..c109d624e 100644 --- a/olp-cpp-sdk-authentication/src/AuthenticationClientImpl.cpp +++ b/olp-cpp-sdk-authentication/src/AuthenticationClientImpl.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2020-2025 HERE Europe B.V. + * Copyright (C) 2020-2026 HERE Europe B.V. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -26,10 +26,9 @@ #include #include -#include -#include -#include -#include +#include +#include +#include #include #include #include @@ -116,17 +115,13 @@ void RetryDelay(const client::RetrySettings& retry_settings, size_t retry) { client::OlpClient::RequestBodyType GenerateAppleSignInBody( const AppleSignInProperties& sign_in_properties) { - rapidjson::StringBuffer data; - rapidjson::Writer writer(data); - writer.StartObject(); + boost::json::object json_object; - writer.Key(kGrantType); - writer.String(kAppleGrantType); + json_object[kGrantType] = kAppleGrantType; - auto write_field = [&writer](const char* key, const std::string& value) { + auto write_field = [&json_object](const char* key, const std::string& value) { if (!value.empty()) { - writer.Key(key); - writer.String(value.c_str()); + json_object[key] = value; } }; @@ -137,9 +132,8 @@ client::OlpClient::RequestBodyType GenerateAppleSignInBody( write_field(kCountryCode, sign_in_properties.GetCountryCode()); write_field(kLanguage, sign_in_properties.GetLanguage()); - writer.EndObject(); - auto content = data.GetString(); - return std::make_shared(content, content + data.GetSize()); + auto content = boost::json::serialize(json_object); + return std::make_shared(content.begin(), content.end()); } client::HttpResponse CallApi(const client::OlpClient& client, @@ -219,20 +213,26 @@ olp::client::HttpResponse AuthenticationClientImpl::CallAuth( SignInResult AuthenticationClientImpl::ParseAuthResponse( int status, std::stringstream& auth_response) { - auto document = std::make_shared(); - rapidjson::IStreamWrapper stream(auth_response); - document->ParseStream(stream); + boost::json::error_code ec; + auto document = boost::json::parse(auth_response, ec); return std::make_shared( - status, olp::http::HttpErrorToString(status), document); + status, olp::http::HttpErrorToString(status), + ec.failed() || !document.is_object() + ? nullptr + : std::make_shared( + std::move(document.as_object()))); } SignInUserResult AuthenticationClientImpl::ParseUserAuthResponse( int status, std::stringstream& auth_response) { - auto document = std::make_shared(); - rapidjson::IStreamWrapper stream(auth_response); - document->ParseStream(stream); + boost::json::error_code ec; + auto document = boost::json::parse(auth_response, ec); return std::make_shared( - status, olp::http::HttpErrorToString(status), document); + status, olp::http::HttpErrorToString(status), + ec.failed() || !document.is_object() + ? nullptr + : std::make_shared( + std::move(document.as_object()))); } template @@ -397,23 +397,24 @@ client::CancellationToken AuthenticationClientImpl::SignInClient( TimeResponse AuthenticationClientImpl::ParseTimeResponse( std::stringstream& payload) { - rapidjson::Document document; - rapidjson::IStreamWrapper stream(payload); - document.ParseStream(stream); + boost::json::error_code ec; + auto json_value = boost::json::parse(payload, ec); - if (!document.IsObject()) { + if (ec.failed() || !json_value.is_object()) { return client::ApiError(client::ErrorCode::InternalFailure, "JSON document root is not an Object type"); } - const auto timestamp_it = document.FindMember("timestamp"); - if (timestamp_it == document.MemberEnd() || !timestamp_it->value.IsUint()) { + auto& object = json_value.as_object(); + const auto timestamp_it = object.find("timestamp"); + if (timestamp_it == object.end() || (!timestamp_it->value().is_uint64() && + !timestamp_it->value().is_int64())) { return client::ApiError( client::ErrorCode::InternalFailure, "JSON document must contain timestamp integer field"); } - return timestamp_it->value.GetUint(); + return timestamp_it->value().to_number(); } TimeResponse AuthenticationClientImpl::GetTimeFromServer( @@ -622,10 +623,14 @@ client::CancellationToken AuthenticationClientImpl::SignUpHereUser( return client::ApiError(status, response_text); } - auto document = std::make_shared(); - document->Parse(response_text.c_str()); + boost::json::error_code ec; + auto document = boost::json::parse(response_text, ec); return {std::make_shared( - status, olp::http::HttpErrorToString(status), document)}; + status, olp::http::HttpErrorToString(status), + ec.failed() || !document.is_object() + ? nullptr + : std::make_shared( + std::move(document.as_object())))}; }; return AddTask(settings_.task_scheduler, pending_requests_, @@ -667,10 +672,14 @@ client::CancellationToken AuthenticationClientImpl::SignOut( return client::ApiError(status, response_text); } - auto document = std::make_shared(); - document->Parse(response_text.c_str()); + boost::json::error_code ec; + auto document = boost::json::parse(response_text, ec); return {std::make_shared( - status, olp::http::HttpErrorToString(status), document)}; + status, olp::http::HttpErrorToString(status), + ec.failed() || !document.is_object() + ? nullptr + : std::make_shared( + std::move(document.as_object())))}; }; return AddTask(settings_.task_scheduler, pending_requests_, @@ -700,24 +709,23 @@ client::CancellationToken AuthenticationClientImpl::IntrospectApp( auto http_result = client.CallApi(kIntrospectAppEndpoint, "GET", {}, {}, {}, nullptr, {}, context); - rapidjson::Document document; - rapidjson::IStreamWrapper stream(http_result.GetRawResponse()); - document.ParseStream(stream); + boost::json::error_code ec; + auto document = boost::json::parse(http_result.GetRawResponse(), ec); if (http_result.GetStatus() != http::HttpStatusCode::OK) { // HttpResult response can be error message or valid json with it. std::string msg = http_result.GetResponseAsString(); - if (!document.HasParseError() && document.HasMember(Constants::MESSAGE)) { - msg = document[Constants::MESSAGE].GetString(); + if (!ec.failed() && document.as_object().contains(Constants::MESSAGE)) { + msg = document.as_object()[Constants::MESSAGE].as_string().c_str(); } return client::ApiError({http_result.GetStatus(), msg}); } - if (document.HasParseError()) { + if (ec.failed() || !document.is_object()) { return client::ApiError({static_cast(http::ErrorCode::UNKNOWN_ERROR), "Failed to parse response"}); } - return GetIntrospectAppResult(document); + return GetIntrospectAppResult(document.as_object()); }; return AddTask(settings_.task_scheduler, pending_requests_, @@ -747,25 +755,27 @@ client::CancellationToken AuthenticationClientImpl::Authorize( GenerateAuthorizeBody(request), kApplicationJson, context); - rapidjson::Document document; - rapidjson::IStreamWrapper stream(http_result.GetRawResponse()); - document.ParseStream(stream); + boost::json::error_code ec; + auto document = boost::json::parse(http_result.GetRawResponse(), ec); if (http_result.GetStatus() != http::HttpStatusCode::OK) { // HttpResult response can be error message or valid json with it. std::string msg = http_result.GetResponseAsString(); - if (!document.HasParseError() && document.HasMember(Constants::MESSAGE)) { - msg = document[Constants::MESSAGE].GetString(); + if (!ec.failed() && document.as_object().contains(Constants::MESSAGE)) { + msg = document.as_object()[Constants::MESSAGE].as_string().c_str(); } return client::ApiError({http_result.GetStatus(), msg}); - } else if (!document.HasParseError() && - document.HasMember(Constants::ERROR_CODE) && - document[Constants::ERROR_CODE].IsInt()) { + } + + if (!ec.failed() && document.as_object().contains(Constants::ERROR_CODE) && + document.as_object()[Constants::ERROR_CODE].is_int64()) { std::string msg = "Error code: " + - std::to_string(document[Constants::ERROR_CODE].GetInt()); - if (document.HasMember(Constants::MESSAGE)) { + std::to_string( + document.as_object()[Constants::ERROR_CODE].as_int64()); + if (document.as_object().contains(Constants::MESSAGE)) { msg.append(" ("); - msg.append(document[Constants::MESSAGE].GetString()); + msg.append( + document.as_object()[Constants::MESSAGE].as_string().c_str()); msg.append(")"); } @@ -773,12 +783,12 @@ client::CancellationToken AuthenticationClientImpl::Authorize( {static_cast(http::ErrorCode::UNKNOWN_ERROR), msg}); } - if (document.HasParseError()) { + if (ec.failed() || !document.is_object()) { return client::ApiError({static_cast(http::ErrorCode::UNKNOWN_ERROR), "Failed to parse response"}); } - return GetAuthorizeResult(document); + return GetAuthorizeResult(document.as_object()); }; return AddTask(settings_.task_scheduler, pending_requests_, std::move(task), @@ -819,237 +829,187 @@ client::OlpClient::RequestBodyType AuthenticationClientImpl::GenerateClientBody( return std::make_shared(content.data(), content.data() + content.size()); }; - rapidjson::StringBuffer data; - rapidjson::Writer writer(data); - writer.StartObject(); - writer.Key(kGrantType); - writer.String(kClientGrantType); + boost::json::object object; + + object[kGrantType] = kClientGrantType; auto expires_in = static_cast(properties.expires_in.count()); if (expires_in > 0) { - writer.Key(Constants::EXPIRES_IN); - writer.Uint(expires_in); + object[Constants::EXPIRES_IN] = expires_in; } if (properties.scope) { - writer.Key(kScope); - writer.String(properties.scope->c_str()); + object[kScope] = properties.scope.get(); } if (properties.device_id) { - writer.Key(kDeviceId); - writer.String(properties.device_id->c_str()); + object[kDeviceId] = properties.device_id.get(); } - writer.EndObject(); - auto content = data.GetString(); - return std::make_shared(content, content + data.GetSize()); + auto content = boost::json::serialize(object); + return std::make_shared(content.begin(), content.end()); } client::OlpClient::RequestBodyType AuthenticationClientImpl::GenerateUserBody( const UserProperties& properties) { - rapidjson::StringBuffer data; - rapidjson::Writer writer(data); - writer.StartObject(); + boost::json::object object; - writer.Key(kGrantType); - writer.String(kUserGrantType); + object[kGrantType] = kUserGrantType; if (!properties.email.empty()) { - writer.Key(kEmail); - writer.String(properties.email.c_str()); + object[kEmail] = properties.email; } if (!properties.password.empty()) { - writer.Key(kPassword); - writer.String(properties.password.c_str()); + object[kPassword] = properties.password; } if (properties.expires_in > 0) { - writer.Key(Constants::EXPIRES_IN); - writer.Uint(properties.expires_in); + object[Constants::EXPIRES_IN] = properties.expires_in; } - writer.EndObject(); - auto content = data.GetString(); - return std::make_shared(content, content + data.GetSize()); + + auto content = boost::json::serialize(object); + return std::make_shared(content.begin(), content.end()); } client::OlpClient::RequestBodyType AuthenticationClientImpl::GenerateFederatedBody( const FederatedSignInType type, const FederatedProperties& properties) { - rapidjson::StringBuffer data; - rapidjson::Writer writer(data); - writer.StartObject(); + boost::json::object object; - writer.Key(kGrantType); switch (type) { case FederatedSignInType::FacebookSignIn: - writer.String(kFacebookGrantType); + object[kGrantType] = kFacebookGrantType; break; case FederatedSignInType::ArcgisSignIn: - writer.String(kArcgisGrantType); + object[kGrantType] = kArcgisGrantType; break; default: return nullptr; } if (!properties.access_token.empty()) { - writer.Key(Constants::ACCESS_TOKEN); - writer.String(properties.access_token.c_str()); + object[Constants::ACCESS_TOKEN] = properties.access_token; } if (!properties.country_code.empty()) { - writer.Key(kCountryCode); - writer.String(properties.country_code.c_str()); + object[kCountryCode] = properties.country_code; } if (!properties.language.empty()) { - writer.Key(kLanguage); - writer.String(properties.language.c_str()); + object[kLanguage] = properties.language; } if (!properties.email.empty()) { - writer.Key(kEmail); - writer.String(properties.email.c_str()); + object[kEmail] = properties.email; } if (properties.expires_in > 0) { - writer.Key(Constants::EXPIRES_IN); - writer.Uint(properties.expires_in); + object[Constants::EXPIRES_IN] = properties.expires_in; } - writer.EndObject(); - auto content = data.GetString(); - return std::make_shared(content, content + data.GetSize()); + auto content = boost::json::serialize(object); + return std::make_shared(content.begin(), content.end()); } client::OlpClient::RequestBodyType AuthenticationClientImpl::GenerateRefreshBody( const RefreshProperties& properties) { - rapidjson::StringBuffer data; - rapidjson::Writer writer(data); - writer.StartObject(); + boost::json::object object; - writer.Key(kGrantType); - writer.String(kRefreshGrantType); + object[kGrantType] = kRefreshGrantType; if (!properties.access_token.empty()) { - writer.Key(Constants::ACCESS_TOKEN); - writer.String(properties.access_token.c_str()); + object[Constants::ACCESS_TOKEN] = properties.access_token; } if (!properties.refresh_token.empty()) { - writer.Key(Constants::REFRESH_TOKEN); - writer.String(properties.refresh_token.c_str()); + object[Constants::REFRESH_TOKEN] = properties.refresh_token; } if (properties.expires_in > 0) { - writer.Key(Constants::EXPIRES_IN); - writer.Uint(properties.expires_in); + object[Constants::EXPIRES_IN] = properties.expires_in; } - writer.EndObject(); - auto content = data.GetString(); - return std::make_shared(content, content + data.GetSize()); + + auto content = boost::json::serialize(object); + return std::make_shared(content.begin(), content.end()); } client::OlpClient::RequestBodyType AuthenticationClientImpl::GenerateSignUpBody( const SignUpProperties& properties) { - rapidjson::StringBuffer data; - rapidjson::Writer writer(data); - writer.StartObject(); + boost::json::object object; if (!properties.email.empty()) { - writer.Key(kEmail); - writer.String(properties.email.c_str()); + object[kEmail] = properties.email; } if (!properties.password.empty()) { - writer.Key(kPassword); - writer.String(properties.password.c_str()); + object[kPassword] = properties.password; } if (!properties.date_of_birth.empty()) { - writer.Key(kDateOfBirth); - writer.String(properties.date_of_birth.c_str()); + object[kDateOfBirth] = properties.date_of_birth; } if (!properties.first_name.empty()) { - writer.Key(kFirstName); - writer.String(properties.first_name.c_str()); + object[kFirstName] = properties.first_name; } if (!properties.last_name.empty()) { - writer.Key(kLastName); - writer.String(properties.last_name.c_str()); + object[kLastName] = properties.last_name; } if (!properties.country_code.empty()) { - writer.Key(kCountryCode); - writer.String(properties.country_code.c_str()); + object[kCountryCode] = properties.country_code; } if (!properties.language.empty()) { - writer.Key(kLanguage); - writer.String(properties.language.c_str()); + object[kLanguage] = properties.language; } if (properties.marketing_enabled) { - writer.Key(kMarketingEnabled); - writer.Bool(true); + object[kMarketingEnabled] = true; } if (!properties.phone_number.empty()) { - writer.Key(kPhoneNumber); - writer.String(properties.phone_number.c_str()); + object[kPhoneNumber] = properties.phone_number; } if (!properties.realm.empty()) { - writer.Key(kRealm); - writer.String(properties.realm.c_str()); + object[kRealm] = properties.realm; } if (!properties.invite_token.empty()) { - writer.Key(kInviteToken); - writer.String(properties.invite_token.c_str()); + object[kInviteToken] = properties.invite_token; } - writer.EndObject(); - auto content = data.GetString(); - return std::make_shared(content, content + data.GetSize()); + auto content = boost::json::serialize(object); + return std::make_shared(content.begin(), content.end()); } client::OlpClient::RequestBodyType AuthenticationClientImpl::GenerateAcceptTermBody( const std::string& reacceptance_token) { - rapidjson::StringBuffer data; - rapidjson::Writer writer(data); - writer.StartObject(); + boost::json::object object; - writer.Key(kTermsReacceptanceToken); - writer.String(reacceptance_token.c_str()); + object[kTermsReacceptanceToken] = reacceptance_token; - writer.EndObject(); - auto content = data.GetString(); - return std::make_shared(content, content + data.GetSize()); + auto content = boost::json::serialize(object); + return std::make_shared(content.begin(), content.end()); } client::OlpClient::RequestBodyType AuthenticationClientImpl::GenerateAuthorizeBody( const AuthorizeRequest& properties) { - rapidjson::StringBuffer data; - rapidjson::Writer writer(data); - writer.StartObject(); - writer.Key(kServiceId); - writer.String(properties.GetServiceId().c_str()); - writer.Key(kActions); - writer.StartArray(); - for (const auto& action : properties.GetActions()) { - writer.StartObject(); - writer.Key(kAction); - writer.String(action.first.c_str()); - if (!action.second.empty()) { - writer.Key(kResource); - writer.String(action.second.c_str()); + boost::json::object object; + + object[kServiceId] = properties.GetServiceId(); + + { + boost::json::array actions; + for (const auto& action : properties.GetActions()) { + boost::json::object action_value; + action_value[kAction] = action.first; + if (!action.second.empty()) { + action_value.emplace(kResource, action.second); + } + actions.emplace_back(std::move(action_value)); } - writer.EndObject(); + object.emplace(kActions, std::move(actions)); } - writer.EndArray(); - writer.Key(kDiagnostics); - writer.Bool(properties.GetDiagnostics()); + object[kDiagnostics] = properties.GetDiagnostics(); // default value is 'and', ignore parameter if operator type is 'and' if (properties.GetOperatorType() == AuthorizeRequest::DecisionOperatorType::kOr) { - writer.Key(kOperator); - writer.String("or"); + object[kOperator] = "or"; } - writer.EndObject(); - auto content = data.GetString(); - return std::make_shared(content, content + data.GetSize()); + auto content = boost::json::serialize(object); + return std::make_shared(content.begin(), content.end()); } std::string AuthenticationClientImpl::GenerateUid() const { diff --git a/olp-cpp-sdk-authentication/src/AuthenticationClientUtils.cpp b/olp-cpp-sdk-authentication/src/AuthenticationClientUtils.cpp index 7de7dccca..27d3acfea 100644 --- a/olp-cpp-sdk-authentication/src/AuthenticationClientUtils.cpp +++ b/olp-cpp-sdk-authentication/src/AuthenticationClientUtils.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2020-2024 HERE Europe B.V. + * Copyright (C) 2020-2026 HERE Europe B.V. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -25,10 +25,9 @@ #include #include -#include -#include -#include -#include +#include +#include +#include #include "Constants.h" #include "ResponseFromJsonBuilder.h" #include "olp/core/http/NetworkResponse.h" @@ -71,25 +70,25 @@ std::string Base64Encode(const Crypto::Sha256Digest& digest) { return ret; } -Response Parse(client::HttpResponse& http_response) { - rapidjson::IStreamWrapper stream(http_response.GetRawResponse()); - rapidjson::Document document; - document.ParseStream(stream); +Response Parse(client::HttpResponse& http_response) { + boost::json::error_code ec; + auto document = boost::json::parse(http_response.GetRawResponse(), ec); if (http_response.GetStatus() != http::HttpStatusCode::OK) { // HttpResult response can be error message or valid json with it. std::string msg = http_response.GetResponseAsString(); - if (!document.HasParseError() && document.HasMember(Constants::MESSAGE)) { - msg = document[Constants::MESSAGE].GetString(); + if (!ec.failed() && document.is_object() && + document.as_object().contains(Constants::MESSAGE)) { + msg = document.as_object()[Constants::MESSAGE].get_string().c_str(); } return client::ApiError({http_response.GetStatus(), msg}); } - if (document.HasParseError()) { + if (ec.failed() || !document.is_object()) { return client::ApiError({static_cast(http::ErrorCode::UNKNOWN_ERROR), "Failed to parse response"}); } - return Response(std::move(document)); + return {std::move(document).as_object()}; } } // namespace @@ -138,7 +137,7 @@ porting::optional GetTimestampFromHeaders( return porting::none; } -IntrospectAppResult GetIntrospectAppResult(const rapidjson::Document& doc) { +IntrospectAppResult GetIntrospectAppResult(const boost::json::object& doc) { return ResponseFromJsonBuilder::Build(doc) .Value(Constants::CLIENT_ID, &IntrospectAppResult::SetClientId) .Value(Constants::NAME, &IntrospectAppResult::SetName) @@ -169,22 +168,25 @@ DecisionType GetDecision(const std::string& str) { : DecisionType::kDeny; } -std::vector GetDiagnostics(rapidjson::Document& doc) { +std::vector GetDiagnostics(boost::json::object& doc) { std::vector results; - const auto& array = doc[Constants::DIAGNOSTICS].GetArray(); - for (auto& element : array) { + auto& array = doc[Constants::DIAGNOSTICS].get_array(); + for (auto& element_value : array) { + auto& element = element_value.get_object(); ActionResult action; - if (element.HasMember(Constants::DECISION)) { - action.SetDecision(GetDecision(element[Constants::DECISION].GetString())); + if (element.contains(Constants::DECISION)) { + action.SetDecision( + GetDecision(element[Constants::DECISION].get_string().c_str())); // get permissions if avialible - if (element.HasMember(Constants::PERMISSIONS) && - element[Constants::PERMISSIONS].IsArray()) { + if (element.contains(Constants::PERMISSIONS) && + element[Constants::PERMISSIONS].is_array()) { std::vector permissions; const auto& permissions_array = - element[Constants::PERMISSIONS].GetArray(); + element[Constants::PERMISSIONS].get_array(); for (auto& permission_element : permissions_array) { Permission permission = - ResponseFromJsonBuilder::Build(permission_element) + ResponseFromJsonBuilder::Build( + permission_element.get_object()) .Value(Constants::ACTION, &Permission::SetAction) .Value(Constants::DECISION, &Permission::SetDecision, &GetDecision) @@ -201,26 +203,27 @@ std::vector GetDiagnostics(rapidjson::Document& doc) { return results; } -AuthorizeResult GetAuthorizeResult(rapidjson::Document& doc) { +AuthorizeResult GetAuthorizeResult(boost::json::object& doc) { AuthorizeResult result; - if (doc.HasMember(Constants::IDENTITY)) { - auto uris = doc[Constants::IDENTITY].GetObject(); + if (doc.contains(Constants::IDENTITY)) { + auto uris = doc[Constants::IDENTITY].get_object(); - if (uris.HasMember(Constants::CLIENT_ID)) { - result.SetClientId(uris[Constants::CLIENT_ID].GetString()); - } else if (uris.HasMember(Constants::USER_ID)) { - result.SetClientId(uris[Constants::USER_ID].GetString()); + if (uris.contains(Constants::CLIENT_ID)) { + result.SetClientId(uris[Constants::CLIENT_ID].get_string().c_str()); + } else if (uris.contains(Constants::USER_ID)) { + result.SetClientId(uris[Constants::USER_ID].get_string().c_str()); } } - if (doc.HasMember(Constants::DECISION)) { - result.SetDecision(GetDecision(doc[Constants::DECISION].GetString())); + if (doc.contains(Constants::DECISION)) { + result.SetDecision( + GetDecision(doc[Constants::DECISION].get_string().c_str())); } // get diagnostics if available - if (doc.HasMember(Constants::DIAGNOSTICS) && - doc[Constants::DIAGNOSTICS].IsArray()) { + if (doc.contains(Constants::DIAGNOSTICS) && + doc[Constants::DIAGNOSTICS].is_array()) { result.SetActionResults(GetDiagnostics(doc)); } return result; diff --git a/olp-cpp-sdk-authentication/src/AuthenticationClientUtils.h b/olp-cpp-sdk-authentication/src/AuthenticationClientUtils.h index 3904627df..6fdb5cd82 100644 --- a/olp-cpp-sdk-authentication/src/AuthenticationClientUtils.h +++ b/olp-cpp-sdk-authentication/src/AuthenticationClientUtils.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2020-2021 HERE Europe B.V. + * Copyright (C) 2020-2026 HERE Europe B.V. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -19,11 +19,12 @@ #pragma once +#include #include #include #include -#include +#include #include "olp/authentication/AuthenticationCredentials.h" #include "olp/authentication/AuthenticationSettings.h" @@ -78,7 +79,7 @@ porting::optional GetTimestampFromHeaders( * @param doc json document. * @return result for introspect app. */ -IntrospectAppResult GetIntrospectAppResult(const rapidjson::Document& doc); +IntrospectAppResult GetIntrospectAppResult(const boost::json::object& value); /* * @brief Convert string representation of decision to DecisionType. @@ -92,14 +93,14 @@ DecisionType GetDecision(const std::string& str); * @param doc json document. * @return result of ActionResults. */ -std::vector GetDiagnostics(rapidjson::Document& doc); +std::vector GetDiagnostics(boost::json::object& value); /* * @brief Parse json document to AuthorizeResult type. * @param doc json document. * @return result for authorize. */ -AuthorizeResult GetAuthorizeResult(rapidjson::Document& doc); +AuthorizeResult GetAuthorizeResult(boost::json::object& value); /* * @brief Parse HTTP response to UserAccountInfoResponse type or error message. diff --git a/olp-cpp-sdk-authentication/src/BaseResult.cpp b/olp-cpp-sdk-authentication/src/BaseResult.cpp index edd86f7c9..f19399961 100644 --- a/olp-cpp-sdk-authentication/src/BaseResult.cpp +++ b/olp-cpp-sdk-authentication/src/BaseResult.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2019-2021 HERE Europe B.V. + * Copyright (C) 2019-2026 HERE Europe B.V. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -19,8 +19,10 @@ #include "BaseResult.h" -#include -#include +#include + +#include +#include #include "Constants.h" #include "olp/core/http/HttpStatusCode.h" @@ -35,52 +37,49 @@ static const char* ERROR_MESSAGE = "message"; static const char* LINE_END = "."; BaseResult::BaseResult(int status, std::string error, - std::shared_ptr json_document) + std::shared_ptr json_document) : status_() { status_ = status; error_.message = std::move(error); - is_valid_ = (json_document && !json_document->HasParseError()); + is_valid_ = json_document != nullptr; // If HTTP error, try to get error details - if (!HasError() || !is_valid_ || !json_document->HasMember(ERROR_CODE)) { + if (!HasError() || !is_valid_ || !json_document->contains(ERROR_CODE)) { return; } // The JSON document has an error code member, so save full JSON content to // the `full_message_` string. - rapidjson::StringBuffer buffer; - rapidjson::Writer writer(buffer); - json_document->Accept(writer); - full_message_ = buffer.GetString(); + full_message_ = boost::json::serialize(*json_document); - if (json_document->HasMember(ERROR_ID)) { - error_.error_id = (*json_document)[ERROR_ID].GetString(); + if (json_document->contains(ERROR_ID)) { + error_.error_id = (*json_document)[ERROR_ID].get_string().c_str(); } // Enhance error message with network response error details - error_.code = (*json_document)[ERROR_CODE].GetUint(); + error_.code = (*json_document)[ERROR_CODE].to_number(); - if (!json_document->HasMember(ERROR_MESSAGE)) { + if (!json_document->contains(ERROR_MESSAGE)) { return; } - std::string message = (*json_document)[ERROR_MESSAGE].GetString(); - if (!json_document->HasMember(ERROR_FIELDS)) { + std::string message = (*json_document)[ERROR_MESSAGE].get_string().c_str(); + if (!json_document->contains(ERROR_FIELDS)) { error_.message = message; return; } error_.message = message.substr(0, message.find_first_of(LINE_END) + 1); - const rapidjson::Value& fields = (*json_document)[ERROR_FIELDS]; - if (fields.GetType() == rapidjson::kArrayType) { - for (rapidjson::SizeType i = 0u; i < fields.Size(); i++) { - const rapidjson::Value& field = fields[i]; - if (field.HasMember(ERROR_MESSAGE)) { + auto& fields = (*json_document)[ERROR_FIELDS]; + if (auto* fields_array = fields.if_array()) { + for (auto& field : *fields_array) { + if (field.is_object() && field.as_object().contains(ERROR_MESSAGE)) { ErrorField error_field; - error_field.name = field[FIELD_NAME].GetString(); - error_field.code = field[ERROR_CODE].GetUint(); - error_field.message = field[ERROR_MESSAGE].GetString(); + error_field.name = field.as_object()[FIELD_NAME].get_string().c_str(); + error_field.code = field.as_object()[ERROR_CODE].to_number(); + error_field.message = + field.as_object()[ERROR_MESSAGE].get_string().c_str(); error_fields_.emplace_back(error_field); } } diff --git a/olp-cpp-sdk-authentication/src/BaseResult.h b/olp-cpp-sdk-authentication/src/BaseResult.h index cd581275f..e0dae31c2 100644 --- a/olp-cpp-sdk-authentication/src/BaseResult.h +++ b/olp-cpp-sdk-authentication/src/BaseResult.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2019-2021 HERE Europe B.V. + * Copyright (C) 2019-2026 HERE Europe B.V. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -24,7 +24,7 @@ #include #include -#include +#include #include "olp/authentication/ErrorResponse.h" @@ -33,7 +33,7 @@ namespace authentication { class BaseResult { public: BaseResult(int status, std::string error, - std::shared_ptr json_document = nullptr); + std::shared_ptr json_document = nullptr); virtual ~BaseResult(); /** diff --git a/olp-cpp-sdk-authentication/src/ResponseFromJsonBuilder.h b/olp-cpp-sdk-authentication/src/ResponseFromJsonBuilder.h index 8d4ee37d5..ff49374ac 100644 --- a/olp-cpp-sdk-authentication/src/ResponseFromJsonBuilder.h +++ b/olp-cpp-sdk-authentication/src/ResponseFromJsonBuilder.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2020-2021 HERE Europe B.V. + * Copyright (C) 2020-2026 HERE Europe B.V. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -19,6 +19,10 @@ #pragma once +#include +#include +#include + #include #include @@ -35,7 +39,8 @@ struct Identity { template class ResponseFromJsonBuilder { - using JsonValue = rapidjson::Document::ValueType; + using JsonDoc = boost::json::object; + using JsonValue = boost::json::value; public: template @@ -46,16 +51,16 @@ class ResponseFromJsonBuilder { const std::string kLogTag = "ResponseFromJsonBuilder"; public: - explicit BuilderHelper(const JsonValue& json_value) : json_{json_value} {} + explicit BuilderHelper(const JsonDoc& json_value) : json_{json_value} {} template BuilderHelper& Value(const char* name, void (TargetType::*set_fn)(ArgType), Projection projection = {}) { using CompatibleType = decltype(GetCompatibleType()); fields_.emplace(name, [=](TargetType& target_obj, - const JsonValue& value) { - if (value.Is()) { - (target_obj.*set_fn)(projection(value.Get())); + const JsonValue& json_value) { + if (auto value = If(json_value)) { + (target_obj.*set_fn)(projection(*value)); } else { OLP_SDK_LOG_WARNING_F(kLogTag, "Wrong type, response=%s, field=%s", kTargetTypeName.c_str(), name); @@ -71,13 +76,13 @@ class ResponseFromJsonBuilder { decltype(GetCompatibleType()); fields_.emplace(name, [=](TargetType& target_obj, const JsonValue& value) { - if (value.IsArray()) { - const auto& array = value.GetArray(); + if (value.is_array()) { + const auto& array = value.get_array(); ArrayType array_result; - array_result.reserve(array.Size()); + array_result.reserve(array.size()); for (const auto& element : array) { - if (element.Is()) { - array_result.push_back(element.Get()); + if (auto element_value = If(element)) { + array_result.push_back(*element_value); } } (target_obj.*set_fn)(std::move(array_result)); @@ -92,12 +97,12 @@ class ResponseFromJsonBuilder { TargetType Finish() { TargetType result; - auto it = json_.MemberBegin(); - auto it_end = json_.MemberEnd(); + auto it = json_.cbegin(); + auto it_end = json_.cend(); for (; it != it_end; ++it) { - auto find_it = fields_.find(std::string{it->name.GetString()}); + auto find_it = fields_.find(std::string{it->key_c_str()}); if (find_it != fields_.end()) { - find_it->second(result, it->value); + find_it->second(result, it->value()); // erasing already processed value fields_.erase(find_it); continue; @@ -105,7 +110,7 @@ class ResponseFromJsonBuilder { OLP_SDK_LOG_WARNING_F(kLogTag, "Unexpected value, response=%s, field=%s", - kTargetTypeName.c_str(), it->name.GetString()); + kTargetTypeName.c_str(), it->key_c_str()); } // in the ideal scenario all fields should be processed @@ -133,11 +138,39 @@ class ResponseFromJsonBuilder { std::is_same::value>::type> int64_t GetCompatibleType(); + template ::value>::type> + const bool* If(const JsonValue& value) { + return value.if_bool(); + } + + template ::value || + std::is_same::value>::type> + const int64_t* If(const JsonValue& value) { + return value.if_int64(); + } + + template ::value>::type> + const uint64_t* If(const JsonValue& value) { + return value.if_uint64(); + } + + template ::value>::type> + porting::optional If(const JsonValue& value) { + if (auto* str = value.if_string()) { + return str->c_str(); + } + return nullptr; + } + using Fields = std::unordered_map>; - const JsonValue& json_; + const JsonDoc& json_; Fields fields_; }; diff --git a/olp-cpp-sdk-authentication/src/SignInResultImpl.cpp b/olp-cpp-sdk-authentication/src/SignInResultImpl.cpp index 96cfa8d7b..334de6cb1 100644 --- a/olp-cpp-sdk-authentication/src/SignInResultImpl.cpp +++ b/olp-cpp-sdk-authentication/src/SignInResultImpl.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2019-2025 HERE Europe B.V. + * Copyright (C) 2019-2026 HERE Europe B.V. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -19,6 +19,8 @@ #include "SignInResultImpl.h" +#include + #include "Constants.h" #include "olp/core/http/HttpStatusCode.h" @@ -33,45 +35,43 @@ constexpr auto kTokenTypeSnakeCase = "token_type"; constexpr auto kAccessTokenSnakeCase = "access_token"; constexpr auto kExpiresInSnakeCase = "expires_in"; -bool HasAccessToken(const rapidjson::Document& document) { - return document.HasMember(Constants::ACCESS_TOKEN) || - document.HasMember(kAccessTokenSnakeCase); +bool HasAccessToken(const boost::json::object& document) { + return document.contains(Constants::ACCESS_TOKEN) || + document.contains(kAccessTokenSnakeCase); } -std::string ParseAccessToken(const rapidjson::Document& document) { - if (document.HasMember(Constants::ACCESS_TOKEN)) { - return document[Constants::ACCESS_TOKEN].GetString(); +std::string ParseAccessToken(const boost::json::object& document) { + if (document.contains(Constants::ACCESS_TOKEN)) { + return document.at(Constants::ACCESS_TOKEN).get_string().c_str(); } - - return document[kAccessTokenSnakeCase].GetString(); + return document.at(kAccessTokenSnakeCase).get_string().c_str(); } -bool HasExpiresIn(const rapidjson::Document& document) { - return document.HasMember(Constants::EXPIRES_IN) || - document.HasMember(kExpiresInSnakeCase); +bool HasExpiresIn(const boost::json::object& document) { + return document.contains(Constants::EXPIRES_IN) || + document.contains(kExpiresInSnakeCase); } -unsigned ParseExpiresIn(const rapidjson::Document& document) { - if (document.HasMember(Constants::EXPIRES_IN)) { - return document[Constants::EXPIRES_IN].GetUint(); +uint64_t ParseExpiresIn(const boost::json::object& document) { + if (document.contains(Constants::EXPIRES_IN)) { + return document.at(Constants::EXPIRES_IN).to_number(); } - return document[kExpiresInSnakeCase].GetUint(); + return document.at(kExpiresInSnakeCase).to_number(); } -bool HasTokenType(const rapidjson::Document& document) { - return document.HasMember(kTokenType) || - document.HasMember(kTokenTypeSnakeCase); +bool HasTokenType(const boost::json::object& document) { + return document.contains(kTokenType) || + document.contains(kTokenTypeSnakeCase); } -std::string ParseTokenType(const rapidjson::Document& document) { - if (document.HasMember(kTokenType)) { - return document[kTokenType].GetString(); +std::string ParseTokenType(const boost::json::object& document) { + if (document.contains(kTokenType)) { + return document.at(kTokenType).get_string().c_str(); } - - return document[kTokenTypeSnakeCase].GetString(); + return document.at(kTokenTypeSnakeCase).get_string().c_str(); } -bool IsDocumentValid(const rapidjson::Document& document) { +bool IsDocumentValid(const boost::json::object& document) { return HasAccessToken(document) && HasExpiresIn(document) && HasTokenType(document); } @@ -84,7 +84,7 @@ SignInResultImpl::SignInResultImpl() noexcept SignInResultImpl::SignInResultImpl( int status, std::string error, - std::shared_ptr json_document) noexcept + std::shared_ptr json_document) noexcept : BaseResult(status, std::move(error), json_document), expiry_time_(), expires_in_() { @@ -100,17 +100,18 @@ SignInResultImpl::SignInResultImpl( access_token_ = ParseAccessToken(*json_document); if (HasTokenType(*json_document)) token_type_ = ParseTokenType(*json_document); - if (json_document->HasMember(Constants::REFRESH_TOKEN)) - refresh_token_ = (*json_document)[Constants::REFRESH_TOKEN].GetString(); + if (json_document->contains(Constants::REFRESH_TOKEN)) + refresh_token_ = + json_document->at(Constants::REFRESH_TOKEN).get_string().c_str(); if (HasExpiresIn(*json_document)) { const auto expires_in = ParseExpiresIn(*json_document); expiry_time_ = std::time(nullptr) + expires_in; expires_in_ = std::chrono::seconds(expires_in); } - if (json_document->HasMember(kUserId)) - user_identifier_ = (*json_document)[kUserId].GetString(); - if (json_document->HasMember(kScope)) - scope_ = (*json_document)[kScope].GetString(); + if (json_document->contains(kUserId)) + user_identifier_ = json_document->at(kUserId).get_string().c_str(); + if (json_document->contains(kScope)) + scope_ = json_document->at(kScope).get_string().c_str(); } } } diff --git a/olp-cpp-sdk-authentication/src/SignInResultImpl.h b/olp-cpp-sdk-authentication/src/SignInResultImpl.h index 1712f443f..bad5abad5 100644 --- a/olp-cpp-sdk-authentication/src/SignInResultImpl.h +++ b/olp-cpp-sdk-authentication/src/SignInResultImpl.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2019-2021 HERE Europe B.V. + * Copyright (C) 2019-2026 HERE Europe B.V. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -19,10 +19,10 @@ #pragma once +#include #include #include #include -#include #include "BaseResult.h" @@ -34,7 +34,7 @@ class SignInResultImpl : public BaseResult { SignInResultImpl( int status, std::string error, - std::shared_ptr json_document = nullptr) noexcept; + std::shared_ptr json_document = nullptr) noexcept; ~SignInResultImpl() override; @@ -65,7 +65,7 @@ class SignInResultImpl : public BaseResult { */ time_t GetExpiryTime() const; - /** + /** * @brief Gets the access token expiry time in seconds. * @return Duration for which token stays valid. */ diff --git a/olp-cpp-sdk-authentication/src/SignInUserResultImpl.cpp b/olp-cpp-sdk-authentication/src/SignInUserResultImpl.cpp index 36530f40d..10eddcc76 100644 --- a/olp-cpp-sdk-authentication/src/SignInUserResultImpl.cpp +++ b/olp-cpp-sdk-authentication/src/SignInUserResultImpl.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2019-2021 HERE Europe B.V. + * Copyright (C) 2019-2026 HERE Europe B.V. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -19,6 +19,8 @@ #include "SignInUserResultImpl.h" +#include + #include "Constants.h" #include "olp/core/http/HttpStatusCode.h" @@ -40,23 +42,24 @@ SignInUserResultImpl::SignInUserResultImpl() noexcept SignInUserResultImpl::SignInUserResultImpl( int status, std::string error, - std::shared_ptr json_document) noexcept + std::shared_ptr json_document) noexcept : SignInResultImpl(status, std::move(error), json_document) { if (BaseResult::IsValid()) { - if (json_document->HasMember(kTermsReacceptanceToken)) + if (json_document->contains(kTermsReacceptanceToken)) term_acceptance_token_ = - (*json_document)[kTermsReacceptanceToken].GetString(); - if (json_document->HasMember(kTermsUrls)) { - rapidjson::Document::Object obj = - (*json_document)[kTermsUrls].GetObject(); - if (obj.HasMember(kTermsOfServiceUrl)) - terms_of_service_url_ = obj[kTermsOfServiceUrl].GetString(); - if (obj.HasMember(kTermsOfServiceUrlJson)) - terms_of_service_url_json_ = obj[kTermsOfServiceUrlJson].GetString(); - if (obj.HasMember(kPrivatePolicyUrl)) - private_policy_url_ = obj[kPrivatePolicyUrl].GetString(); - if (obj.HasMember(kPrivatePolicyUrlJson)) - private_policy_url_json_ = obj[kPrivatePolicyUrlJson].GetString(); + (*json_document)[kTermsReacceptanceToken].get_string().c_str(); + if (json_document->contains(kTermsUrls)) { + auto& obj = (*json_document)[kTermsUrls].get_object(); + if (obj.contains(kTermsOfServiceUrl)) + terms_of_service_url_ = obj[kTermsOfServiceUrl].get_string().c_str(); + if (obj.contains(kTermsOfServiceUrlJson)) + terms_of_service_url_json_ = + obj[kTermsOfServiceUrlJson].get_string().c_str(); + if (obj.contains(kPrivatePolicyUrl)) + private_policy_url_ = obj[kPrivatePolicyUrl].get_string().c_str(); + if (obj.contains(kPrivatePolicyUrlJson)) + private_policy_url_json_ = + obj[kPrivatePolicyUrlJson].get_string().c_str(); } } } diff --git a/olp-cpp-sdk-authentication/src/SignInUserResultImpl.h b/olp-cpp-sdk-authentication/src/SignInUserResultImpl.h index c6fd5218c..15425e57f 100644 --- a/olp-cpp-sdk-authentication/src/SignInUserResultImpl.h +++ b/olp-cpp-sdk-authentication/src/SignInUserResultImpl.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2019-2021 HERE Europe B.V. + * Copyright (C) 2019-2026 HERE Europe B.V. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -20,6 +20,7 @@ #pragma once #include +#include #include #include "SignInResultImpl.h" @@ -41,7 +42,7 @@ class SignInUserResultImpl : public SignInResultImpl { SignInUserResultImpl( int status, std::string error, - std::shared_ptr json_document = nullptr) noexcept; + std::shared_ptr json_document = nullptr) noexcept; ~SignInUserResultImpl() override; diff --git a/olp-cpp-sdk-authentication/src/SignOutResultImpl.cpp b/olp-cpp-sdk-authentication/src/SignOutResultImpl.cpp index d223919f4..3b381d9c0 100644 --- a/olp-cpp-sdk-authentication/src/SignOutResultImpl.cpp +++ b/olp-cpp-sdk-authentication/src/SignOutResultImpl.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2019-2021 HERE Europe B.V. + * Copyright (C) 2019-2026 HERE Europe B.V. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -19,6 +19,8 @@ #include "SignOutResultImpl.h" +#include + #include "Constants.h" #include "olp/core/http/HttpStatusCode.h" @@ -31,7 +33,7 @@ SignOutResultImpl::SignOutResultImpl() noexcept SignOutResultImpl::SignOutResultImpl( int status, std::string error, - std::shared_ptr json_document) noexcept + std::shared_ptr json_document) noexcept : BaseResult(status, std::move(error), json_document) {} SignOutResultImpl::~SignOutResultImpl() = default; diff --git a/olp-cpp-sdk-authentication/src/SignOutResultImpl.h b/olp-cpp-sdk-authentication/src/SignOutResultImpl.h index 8c13229db..d23dccff5 100644 --- a/olp-cpp-sdk-authentication/src/SignOutResultImpl.h +++ b/olp-cpp-sdk-authentication/src/SignOutResultImpl.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2019 HERE Europe B.V. + * Copyright (C) 2019-2026 HERE Europe B.V. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -33,7 +33,7 @@ class SignOutResultImpl : public BaseResult { SignOutResultImpl( int status, std::string error, - std::shared_ptr json_document = nullptr) noexcept; + std::shared_ptr json_document = nullptr) noexcept; ~SignOutResultImpl() override; }; diff --git a/olp-cpp-sdk-authentication/src/SignUpResultImpl.cpp b/olp-cpp-sdk-authentication/src/SignUpResultImpl.cpp index 27ea17db3..a62e080c3 100644 --- a/olp-cpp-sdk-authentication/src/SignUpResultImpl.cpp +++ b/olp-cpp-sdk-authentication/src/SignUpResultImpl.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2019-2021 HERE Europe B.V. + * Copyright (C) 2019-2026 HERE Europe B.V. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -19,6 +19,8 @@ #include "SignUpResultImpl.h" +#include + #include "Constants.h" #include "olp/core/http/HttpStatusCode.h" @@ -35,11 +37,11 @@ SignUpResultImpl::SignUpResultImpl() noexcept SignUpResultImpl::SignUpResultImpl( int status, std::string error, - std::shared_ptr json_document) noexcept + std::shared_ptr json_document) noexcept : BaseResult(status, std::move(error), json_document) { if (BaseResult::IsValid()) { - if (json_document->HasMember(kUserId)) - user_identifier_ = (*json_document)[kUserId].GetString(); + if (json_document->contains(kUserId)) + user_identifier_ = (*json_document)[kUserId].get_string().c_str(); } } diff --git a/olp-cpp-sdk-authentication/src/SignUpResultImpl.h b/olp-cpp-sdk-authentication/src/SignUpResultImpl.h index 7434d8e0a..e51adf3ee 100644 --- a/olp-cpp-sdk-authentication/src/SignUpResultImpl.h +++ b/olp-cpp-sdk-authentication/src/SignUpResultImpl.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2019-2021 HERE Europe B.V. + * Copyright (C) 2019-2026 HERE Europe B.V. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -23,7 +23,7 @@ #include #include -#include +#include #include "BaseResult.h" @@ -35,7 +35,7 @@ class SignUpResultImpl : public BaseResult { SignUpResultImpl( int status, std::string error, - std::shared_ptr json_document = nullptr) noexcept; + std::shared_ptr json_document = nullptr) noexcept; ~SignUpResultImpl() override; diff --git a/olp-cpp-sdk-authentication/src/TokenEndpointImpl.cpp b/olp-cpp-sdk-authentication/src/TokenEndpointImpl.cpp index 52bf22fa9..640cf5fa9 100644 --- a/olp-cpp-sdk-authentication/src/TokenEndpointImpl.cpp +++ b/olp-cpp-sdk-authentication/src/TokenEndpointImpl.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2021-2024 HERE Europe B.V. + * Copyright (C) 2021-2026 HERE Europe B.V. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -29,10 +29,9 @@ #include #include #include -#include -#include -#include -#include +#include +#include +#include #include #include #include "AuthenticationClientUtils.h" @@ -102,22 +101,24 @@ void RetryDelay(const client::RetrySettings& retry_settings, size_t retry) { } TimeResponse ParseTimeResponse(const std::string& payload) { - rapidjson::Document document; - document.Parse(payload.c_str()); + boost::json::error_code ec; + auto document = boost::json::parse(payload, ec); - if (!document.IsObject()) { + if (!document.is_object()) { return client::ApiError(client::ErrorCode::InternalFailure, "JSON document root is not an Object type"); } - const auto timestamp_it = document.FindMember("timestamp"); - if (timestamp_it == document.MemberEnd() || !timestamp_it->value.IsUint()) { + const auto timestamp_it = document.as_object().find("timestamp"); + if (timestamp_it == document.as_object().end() || + (!timestamp_it->value().is_uint64() && + !timestamp_it->value().is_int64())) { return client::ApiError( client::ErrorCode::InternalFailure, "JSON document must contain timestamp integer field"); } - return timestamp_it->value.GetUint(); + return timestamp_it->value().to_number(); } std::string GenerateUid() { @@ -130,28 +131,22 @@ std::string GenerateUid() { client::OlpClient::RequestBodyType GenerateClientBody( const TokenRequest& token_request, const porting::optional& scope) { - rapidjson::StringBuffer data; - rapidjson::Writer writer(data); - writer.StartObject(); + boost::json::object object; - writer.Key(kGrantType); - writer.String(kClientGrantType); + object[kGrantType] = kClientGrantType; auto expires_in = static_cast(token_request.GetExpiresIn().count()); if (expires_in > 0) { - writer.Key(Constants::EXPIRES_IN); - writer.Uint(expires_in); + object[Constants::EXPIRES_IN] = expires_in; } if (scope) { - writer.Key(kScope); - writer.String(scope->c_str()); + object[kScope] = scope.get(); } - writer.EndObject(); - auto content = data.GetString(); - return std::make_shared(content, content + data.GetSize()); + auto content = boost::json::serialize(object); + return std::make_shared(content.begin(), content.end()); } TimeResponse GetTimeFromServer(client::CancellationContext& context, @@ -334,11 +329,13 @@ SignInResponse TokenEndpointImpl::SignInClient( SignInResult TokenEndpointImpl::ParseAuthResponse( int status, std::stringstream& auth_response) { - auto document = std::make_shared(); - rapidjson::IStreamWrapper stream(auth_response); - document->ParseStream(stream); + boost::json::error_code ec; + auto document = boost::json::parse(auth_response, ec); return std::make_shared( - status, http::HttpErrorToString(status), document); + status, http::HttpErrorToString(status), + ec.failed() || !document.is_object() + ? nullptr + : std::make_shared(document.as_object())); } client::HttpResponse TokenEndpointImpl::CallAuth( diff --git a/olp-cpp-sdk-authentication/tests/SignInResultImplTest.cpp b/olp-cpp-sdk-authentication/tests/SignInResultImplTest.cpp index 08599cc54..3381c0123 100644 --- a/olp-cpp-sdk-authentication/tests/SignInResultImplTest.cpp +++ b/olp-cpp-sdk-authentication/tests/SignInResultImplTest.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2020-2025 HERE Europe B.V. + * Copyright (C) 2020-2026 HERE Europe B.V. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -19,6 +19,7 @@ #include #include +#include #include "../src/SignInResultImpl.h" namespace { @@ -82,8 +83,12 @@ constexpr auto kWrongFormatResponse = TEST(SignInResultImplTest, Constructor) { { SCOPED_TRACE("Valid token"); - auto doc = std::make_shared(); - doc->Parse(kTokenResponse); + + boost::system::error_code error_code; + auto doc = std::make_shared( + boost::json::parse(kTokenResponse, error_code).as_object()); + ASSERT_FALSE(error_code.failed()); + olp::authentication::SignInResultImpl result(olp::http::HttpStatusCode::OK, std::string(), doc); @@ -95,8 +100,12 @@ TEST(SignInResultImplTest, Constructor) { { SCOPED_TRACE("Valid token from snake case response"); - auto doc = std::make_shared(); - doc->Parse(kTokenResponseSnakeCase); + + boost::system::error_code error_code; + auto doc = std::make_shared( + boost::json::parse(kTokenResponseSnakeCase, error_code).as_object()); + ASSERT_FALSE(error_code.failed()); + olp::authentication::SignInResultImpl result(olp::http::HttpStatusCode::OK, std::string(), doc); @@ -108,8 +117,12 @@ TEST(SignInResultImplTest, Constructor) { { SCOPED_TRACE("Bad response"); - auto doc = std::make_shared(); - doc->Parse(kWrongFormatResponse); + + boost::system::error_code error_code; + auto doc = std::make_shared( + boost::json::parse(kWrongFormatResponse, error_code).as_object()); + ASSERT_FALSE(error_code.failed()); + olp::authentication::SignInResultImpl result(olp::http::HttpStatusCode::OK, std::string(), doc); diff --git a/tests/functional/olp-cpp-sdk-authentication/AuthenticationTestUtils.cpp b/tests/functional/olp-cpp-sdk-authentication/AuthenticationTestUtils.cpp index ce5b2c7bd..00313d280 100644 --- a/tests/functional/olp-cpp-sdk-authentication/AuthenticationTestUtils.cpp +++ b/tests/functional/olp-cpp-sdk-authentication/AuthenticationTestUtils.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2019 HERE Europe B.V. + * Copyright (C) 2019-2026 HERE Europe B.V. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -19,26 +19,34 @@ #include "AuthenticationTestUtils.h" -#include #include +#include #ifndef WIN32 #include #endif -#include -#include -#include -#include +#include +#include +#include + #include #include #include #include #include "TestConstants.h" -using namespace ::olp::authentication; - namespace { + +using olp::authentication::kAccessToken; +using olp::authentication::kAndParam; +using olp::authentication::kEqualsParam; +using olp::authentication::kHereAccountStagingURL; +using olp::authentication::kMaxRetryCount; +using olp::authentication::kQuestionParam; +using olp::authentication::kRetryDelayInSecs; +using olp::authentication::kTestUserName; + constexpr auto kFacebookUrl = "https://graph.facebook.com/v2.12"; constexpr auto kId = "id"; @@ -79,8 +87,8 @@ bool AuthenticationTestUtils::CreateFacebookTestUser( unsigned int retry = 0u; do { if (retry > 0u) { - OLP_SDK_LOG_WARNING(__func__, "Request retry attempted (" << retry - << ")"); + OLP_SDK_LOG_WARNING(__func__, + "Request retry attempted (" << retry << ")"); std::this_thread::sleep_for( std::chrono::seconds(retry * kRetryDelayInSecs)); } @@ -89,27 +97,26 @@ bool AuthenticationTestUtils::CreateFacebookTestUser( std::promise promise; auto future = promise.get_future(); - network.Send(request, payload, - [payload, &promise, - &user](const olp::http::NetworkResponse &network_response) { - user.token.status = network_response.GetStatus(); - if (user.token.status == olp::http::HttpStatusCode::OK) { - auto document = std::make_shared(); - rapidjson::IStreamWrapper stream(*payload); - document->ParseStream(stream); - const bool is_valid = - !document->HasParseError() && - document->HasMember(kAccessToken.c_str()) && - document->HasMember(kId); - - if (is_valid) { - user.token.access_token = - (*document)[kAccessToken.c_str()].GetString(); - user.id = (*document)[kId].GetString(); - } - } - promise.set_value(); - }); + network.Send( + request, payload, + [payload, &promise, + &user](const olp::http::NetworkResponse &network_response) { + user.token.status = network_response.GetStatus(); + if (user.token.status == olp::http::HttpStatusCode::OK) { + boost::json::error_code ec; + auto document = boost::json::parse(*payload, ec); + const bool is_valid = !ec.failed() && document.is_object() && + document.as_object().contains(kAccessToken) && + document.as_object().contains(kId); + + if (is_valid) { + user.token.access_token = + document.as_object()[kAccessToken].get_string().c_str(); + user.id = document.as_object()[kId].get_string().c_str(); + } + } + promise.set_value(); + }); future.wait(); } while ((user.token.status < 0) && (++retry < kMaxRetryCount)); @@ -132,8 +139,8 @@ bool AuthenticationTestUtils::DeleteFacebookTestUser( unsigned int retry = 0u; do { if (retry > 0u) { - OLP_SDK_LOG_WARNING(__func__, "Request retry attempted (" << retry - << ")"); + OLP_SDK_LOG_WARNING(__func__, + "Request retry attempted (" << retry << ")"); std::this_thread::sleep_for( std::chrono::seconds(retry * kRetryDelayInSecs)); } @@ -220,8 +227,8 @@ bool AuthenticationTestUtils::GetAccessTokenImpl( unsigned int retry = 0u; do { if (retry > 0u) { - OLP_SDK_LOG_WARNING(__func__, "Request retry attempted (" << retry - << ")"); + OLP_SDK_LOG_WARNING(__func__, + "Request retry attempted (" << retry << ")"); std::this_thread::sleep_for( std::chrono::seconds(retry * kRetryDelayInSecs)); } @@ -230,23 +237,23 @@ bool AuthenticationTestUtils::GetAccessTokenImpl( std::promise promise; auto future = promise.get_future(); - network.Send(request, payload, - [payload, &promise, - &token](const olp::http::NetworkResponse &network_response) { - token.status = network_response.GetStatus(); - if (token.status == olp::http::HttpStatusCode::OK) { - auto document = std::make_shared(); - rapidjson::IStreamWrapper stream(*payload); - document->ParseStream(stream); - bool is_valid = !document->HasParseError() && - document->HasMember(kAccessToken.c_str()); - if (is_valid) { - token.access_token = - (*document)[kAccessToken.c_str()].GetString(); - } - } - promise.set_value(); - }); + network.Send( + request, payload, + [payload, &promise, + &token](const olp::http::NetworkResponse &network_response) { + token.status = network_response.GetStatus(); + if (token.status == olp::http::HttpStatusCode::OK) { + boost::json::error_code ec; + auto document = boost::json::parse(*payload, ec); + const bool is_valid = !ec.failed() && document.is_object() && + document.as_object().contains(kAccessToken); + if (is_valid) { + token.access_token = + document.as_object()[kAccessToken].get_string().c_str(); + } + } + promise.set_value(); + }); future.wait(); } while ((token.status < 0) && (++retry < kMaxRetryCount)); diff --git a/tests/functional/olp-cpp-sdk-authentication/FederatedAuthenticationTest.cpp b/tests/functional/olp-cpp-sdk-authentication/FederatedAuthenticationTest.cpp index 9003077f8..a49db9101 100644 --- a/tests/functional/olp-cpp-sdk-authentication/FederatedAuthenticationTest.cpp +++ b/tests/functional/olp-cpp-sdk-authentication/FederatedAuthenticationTest.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2020 HERE Europe B.V. + * Copyright (C) 2020-2025 HERE Europe B.V. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -17,9 +17,8 @@ * License-Filename: LICENSE */ -#include -#include -#include +#include +#include #include #include @@ -27,8 +26,6 @@ #include "AuthenticationTestUtils.h" #include "TestConstants.h" -using namespace ::olp::authentication; - namespace { class FederatedAuthenticationTest : public AuthenticationCommonTestFixture { @@ -65,23 +62,13 @@ class FederatedAuthenticationTest : public AuthenticationCommonTestFixture { std::string GoogleAuthenticationBody(const std::string& email, const std::string& access_token) { - rapidjson::StringBuffer data; - - rapidjson::Writer writer(data); - writer.StartObject(); - writer.Key("grantType"); - writer.String("google"); - writer.Key("accessToken"); - writer.String(access_token.c_str()); - writer.Key("countryCode"); - writer.String("USA"); - writer.Key("language"); - writer.String("en"); - writer.Key("email"); - writer.String(email.c_str()); - writer.EndObject(); - - return data.GetString(); + boost::json::object object; + object["grantType"] = "google"; + object["accessToken"] = access_token; + object["countryCode"] = "USA"; + object["language"] = "en"; + object["email"] = email; + return boost::json::serialize(object); } protected: