From 74d5ac2e1a98da57afa6b8f4cf4435705006b37a Mon Sep 17 00:00:00 2001 From: ZhangXiufang Date: Mon, 20 Jan 2025 07:46:40 +0000 Subject: [PATCH 1/2] Modify Token007 to support pack/unpack of multiple ServiceTypes of the same type --- .../AgoraDynamicKey/cpp/src/AccessToken2.h | 40 +++++++- DynamicKey/AgoraDynamicKey/cpp/src/Packer.h | 8 ++ .../cpp/test/AccessToken2_test.cpp | 95 ++++++++++++++++++- .../cpp/test/ApaasTokenBuilder_test.cpp | 10 +- .../AgoraDynamicKey/cpp/test/CMakeLists.txt | 4 +- .../cpp/test/EducationTokenBuilder2_test.cpp | 10 +- 6 files changed, 149 insertions(+), 18 deletions(-) diff --git a/DynamicKey/AgoraDynamicKey/cpp/src/AccessToken2.h b/DynamicKey/AgoraDynamicKey/cpp/src/AccessToken2.h index 5f3c523b..b61f6589 100644 --- a/DynamicKey/AgoraDynamicKey/cpp/src/AccessToken2.h +++ b/DynamicKey/AgoraDynamicKey/cpp/src/AccessToken2.h @@ -257,7 +257,7 @@ class AccessToken2 { static std::string Version() { return "007"; } - void AddService(std::unique_ptr service) { services_[service->ServiceType()] = std::move(service); } + void AddService(std::unique_ptr service) { services_.insert(std::make_pair(service->ServiceType(), std::move(service))); } std::string Build() { if (!BuildCheck()) return ""; @@ -285,6 +285,32 @@ class AccessToken2 { return true; } + bool VerifySignature(std::string token, const std::string &app_certificate) { + if (token.substr(0, VERSION_LENGTH) != Version()) { + return false; + } + std::string signature; + std::string app_id; + uint32_t issue_ts; + uint32_t expire; + uint32_t salt; + try { + auto buffer = Decompress(base64Decode(token.substr(VERSION_LENGTH))); + Unpacker unpacker(buffer.data(), buffer.length()); + unpacker >> signature >> app_id >> issue_ts >> expire >> salt; + + auto signing = HmacSign2(Pack(issue_ts), app_certificate, HMAC_SHA256_LENGTH); + signing = HmacSign2(Pack(salt), signing, HMAC_SHA256_LENGTH); + + auto signing_info = Pack(app_id) + Pack(issue_ts) + Pack(expire) + Pack(salt) + unpacker.pop_raw_string_to_end(); + auto gen_signature = HmacSign2(signing, signing_info, HMAC_SHA256_LENGTH); + return signature == gen_signature; + } catch (std::exception &e) { + perror((std::string("VerifySignature error: ") + e.what()).c_str()); + return false; + } + } + std::string GenerateSignature(const std::string &app_certificate) { app_cert_ = app_certificate; if (!BuildCheck()) return ""; @@ -323,10 +349,14 @@ class AccessToken2 { for (auto i = 0; i < service_count; ++i) { uint16_t service_type; *unpacker >> service_type; - - auto service = std::unique_ptr(kServiceCreator.at(service_type)()); + auto service_ptr = kServiceCreator.find(service_type); + if (service_ptr == kServiceCreator.end()) { + perror((std::string("invalid service type ") + std::to_string(service_type)).c_str()); + break; + } + auto service = std::unique_ptr(service_ptr->second()); service->UnpackService(unpacker); - services_[service_type] = std::move(service); + services_.insert(std::make_pair(service_type, std::move(service))); } } @@ -358,7 +388,7 @@ class AccessToken2 { std::string app_cert_; std::string signature_; - std::map> services_; + std::multimap> services_; }; } // namespace tools diff --git a/DynamicKey/AgoraDynamicKey/cpp/src/Packer.h b/DynamicKey/AgoraDynamicKey/cpp/src/Packer.h index 3c2d572d..b886e648 100644 --- a/DynamicKey/AgoraDynamicKey/cpp/src/Packer.h +++ b/DynamicKey/AgoraDynamicKey/cpp/src/Packer.h @@ -313,6 +313,14 @@ class Unpacker return s; } + std::string pop_raw_string_to_end() { + uint32_t length = length_ - position_; + check_size(length, position_); + std::string s = std::string(buffer_ + position_, length); + position_ += length; + return s; + } + const char* buffer() const { return buffer_; } diff --git a/DynamicKey/AgoraDynamicKey/cpp/test/AccessToken2_test.cpp b/DynamicKey/AgoraDynamicKey/cpp/test/AccessToken2_test.cpp index 97422280..73896836 100644 --- a/DynamicKey/AgoraDynamicKey/cpp/test/AccessToken2_test.cpp +++ b/DynamicKey/AgoraDynamicKey/cpp/test/AccessToken2_test.cpp @@ -13,7 +13,6 @@ #include "../src/md5/md5.h" using namespace agora::tools; - class AccessToken2_test : public testing::Test { protected: virtual void SetUp() override { @@ -26,11 +25,34 @@ class AccessToken2_test : public testing::Test { account_ = "2882341273"; expire_ = 600; issue_ts_ = 1111111; + expiredTs_ = time(nullptr) + 3600; room_uuid_ = "123"; role_ = 1; } + std::unique_ptr BuildRtcService(std::string channelName, uint32_t uid, uint32_t expiredTs) { + std::unique_ptr rtc(new ServiceRtc(channelName, uid)); + rtc->AddPrivilege(ServiceRtc::kPrivilegeJoinChannel, expiredTs); + rtc->AddPrivilege(ServiceRtc::kPrivilegePublishAudioStream, expiredTs); + rtc->AddPrivilege(ServiceRtc::kPrivilegePublishVideoStream, expiredTs); + rtc->AddPrivilege(ServiceRtc::kPrivilegePublishDataStream, expiredTs); + return rtc; + } + + std::unique_ptr BuildRtmService(std::string uidStr, uint32_t expiredTs) { + std::unique_ptr rtm(new ServiceRtm(uidStr)); + rtm->AddPrivilege(ServiceRtm::kPrivilegeLogin, expiredTs); + return rtm; + } + + std::unique_ptr BuildRtmStreamServiceAsRtc(std::string channelName, uint32_t uid, uint32_t expiredTs) { + std::unique_ptr rtc(new ServiceRtc(channelName, uid)); + rtc->AddPrivilege(ServiceRtc::kPrivilegeJoinChannel, expiredTs); + rtc->AddPrivilege(ServiceRtc::kPrivilegePublishDataStream, expiredTs); + return rtc; + } + void VerifyService(Service *l, Service *r) { EXPECT_EQ(l->privileges_.size(), r->privileges_.size()); @@ -325,6 +347,72 @@ class AccessToken2_test : public testing::Test { VerifyAccessToken2(expected, &key); } + void TestSameServiceMulti() { + auto rtc_expire = expiredTs_; + auto rtm_expire = expiredTs_ + 100; + auto rtm_stream_expire = expiredTs_ + 200; + + AccessToken2 token(app_id_, app_certificate_, 0, rtc_expire); + + token.AddService(std::move(BuildRtcService(channel_name_, uid_, rtc_expire))); + token.AddService(std::move(BuildRtmService(account_, rtm_expire))); + token.AddService(std::move(BuildRtmStreamServiceAsRtc(channel_name_, uid_, rtm_stream_expire))); + std::string token_str = token.Build(); + AccessToken2 token_parsed; + ASSERT_TRUE(token_parsed.FromString(token_str)); + ASSERT_TRUE(token_parsed.VerifySignature(token_str, app_certificate_)); + + EXPECT_EQ(app_id_, token.app_id_); + EXPECT_EQ(rtc_expire, token.expire_); + + ASSERT_EQ(3, token.services_.size()); + ASSERT_EQ(token.services_.count(ServiceRtc::kServiceType), 2); + ASSERT_EQ(token.services_.count(ServiceRtm::kServiceType), 1); + + + uint32_t cnt = 0; + for (auto srv = token_parsed.services_.begin(); srv != token_parsed.services_.end(); srv++) { + if (srv->first == ServiceRtc::kServiceType) { + if (cnt == 0 ) { + ServiceRtc *rtc = dynamic_cast(srv->second.get()); + EXPECT_EQ(rtc->channel_name_, channel_name_); + EXPECT_EQ(rtc->account_, account_); + EXPECT_EQ(rtc->privileges_[ServiceRtc::kPrivilegeJoinChannel], rtc_expire); + EXPECT_EQ(rtc->privileges_[ServiceRtc::kPrivilegePublishAudioStream], rtc_expire); + EXPECT_EQ(rtc->privileges_[ServiceRtc::kPrivilegePublishVideoStream], rtc_expire); + EXPECT_EQ(rtc->privileges_[ServiceRtc::kPrivilegePublishDataStream], rtc_expire); + } else if (cnt == 1) { + ServiceRtc *rtm_stream = dynamic_cast(srv->second.get()); + EXPECT_EQ(rtm_stream->channel_name_, channel_name_); + EXPECT_EQ(rtm_stream->account_, account_); + EXPECT_EQ(rtm_stream->privileges_[ServiceRtc::kPrivilegeJoinChannel], rtm_stream_expire); + EXPECT_EQ(rtm_stream->privileges_[ServiceRtc::kPrivilegePublishDataStream], rtm_stream_expire); + } + cnt++; + } else if (srv->first == ServiceRtm::kServiceType) { + ServiceRtm * rtm = dynamic_cast(srv->second.get()); + EXPECT_EQ(rtm->user_id_, account_); + EXPECT_EQ(rtm->privileges_[ServiceRtm::kPrivilegeLogin], rtm_expire); + } else { + EXPECT_TRUE(false); + } + } + EXPECT_EQ(token_parsed.GenerateSignature(app_certificate_), token_parsed.signature_); + } + + void TestOldTokenParse() { + std::string token_str = "007eJxTYLjhFiNy2/+8zqRJj20tt73SKA2e3/" + "joPVv4761qZnrOyqYKDJbmBs6OxqYpqWYGySYmZiamSUmJqRaJRoamBmaGScbG7l8EGCKY" + "GBgYGRgYWIAkCIP4TGCSGUyygEkFBvMUcyNjM9PUJEsLYxMLU2NL81TjVOM0yxQTM4OklJ" + "RELgYjCwsjYxNDI3NjJqA5EJM4GUpSi0viS4tTi1jggqxwFrImAAIiLHc="; + AccessToken2 token_parsed; + ASSERT_TRUE(token_parsed.FromString(token_str)); + ASSERT_TRUE(token_parsed.VerifySignature(token_str, app_certificate_)); + EXPECT_EQ(token_parsed.app_id_, app_id_); + EXPECT_EQ(token_parsed.expire_, expire_); + EXPECT_EQ(token_parsed.GenerateSignature(app_certificate_), token_parsed.signature_); + VerifyAccessToken2(token_str, &token_parsed); + } private: std::string app_id_; @@ -337,6 +425,7 @@ class AccessToken2_test : public testing::Test { uint32_t uid_; uint32_t expire_; uint32_t issue_ts_; + uint32_t expiredTs_; int16_t role_; }; @@ -359,3 +448,7 @@ TEST_F(AccessToken2_test, testAccessToken2ApaasUser) { TestAccessToken2ApaasUser TEST_F(AccessToken2_test, testAccessToken2ApaasApp) { TestAccessToken2ApaasApp(); } TEST_F(AccessToken2_test, testAccessToken2WithMultiService) { TestAccessToken2WithMultiService(); } + +TEST_F(AccessToken2_test, testSameServiceMulti) { TestSameServiceMulti(); } + +TEST_F(AccessToken2_test, testOldTokenParse) { TestOldTokenParse(); } \ No newline at end of file diff --git a/DynamicKey/AgoraDynamicKey/cpp/test/ApaasTokenBuilder_test.cpp b/DynamicKey/AgoraDynamicKey/cpp/test/ApaasTokenBuilder_test.cpp index 96b496f4..0132e74d 100644 --- a/DynamicKey/AgoraDynamicKey/cpp/test/ApaasTokenBuilder_test.cpp +++ b/DynamicKey/AgoraDynamicKey/cpp/test/ApaasTokenBuilder_test.cpp @@ -40,7 +40,7 @@ class ApaasTokenBuilder_test : public testing::Test { ASSERT_TRUE(token.services_.count(ServiceRtm::kServiceType)); ASSERT_TRUE(token.services_.count(ServiceChat::kServiceType)); - const auto &apaas_service = dynamic_cast(*token.services_[ServiceApaas::kServiceType]); + const auto &apaas_service = dynamic_cast(*token.services_.find(ServiceApaas::kServiceType)->second); EXPECT_EQ(room_uuid_, apaas_service.room_uuid_); EXPECT_EQ(user_id_, apaas_service.user_uuid_); @@ -49,13 +49,13 @@ class ApaasTokenBuilder_test : public testing::Test { ASSERT_TRUE(apaas_service.privileges_.count(ServiceApaas::kPrivilegeRoomUser)); EXPECT_EQ(expire_, apaas_service.privileges_.at(ServiceApaas::kPrivilegeRoomUser)); - const auto &rtm_service = dynamic_cast(*token.services_[ServiceRtm::kServiceType]); + const auto &rtm_service = dynamic_cast(*token.services_.find(ServiceRtm::kServiceType)->second); EXPECT_EQ(user_id_, rtm_service.user_id_); ASSERT_EQ(1, rtm_service.privileges_.size()); ASSERT_TRUE(rtm_service.privileges_.count(ServiceRtm::kPrivilegeLogin)); EXPECT_EQ(expire_, rtm_service.privileges_.at(ServiceRtm::kPrivilegeLogin)); - const auto &chat_service = dynamic_cast(*token.services_[ServiceChat::kServiceType]); + const auto &chat_service = dynamic_cast(*token.services_.find(ServiceChat::kServiceType)->second); EXPECT_EQ(chat_user_id_, chat_service.user_id_); ASSERT_EQ(1, chat_service.privileges_.size()); ASSERT_TRUE(chat_service.privileges_.count(ServiceChat::kPrivilegeUser)); @@ -73,7 +73,7 @@ class ApaasTokenBuilder_test : public testing::Test { ASSERT_EQ(1, token.services_.size()); ASSERT_TRUE(token.services_.count(ServiceApaas::kServiceType)); - const auto &apaas_service = dynamic_cast(*token.services_[ServiceApaas::kServiceType]); + const auto &apaas_service = dynamic_cast(*token.services_.find(ServiceApaas::kServiceType)->second); EXPECT_EQ("", apaas_service.room_uuid_); EXPECT_EQ(user_id_, apaas_service.user_uuid_); @@ -94,7 +94,7 @@ class ApaasTokenBuilder_test : public testing::Test { ASSERT_EQ(1, token.services_.size()); ASSERT_TRUE(token.services_.count(ServiceApaas::kServiceType)); - const auto &apaas_service = dynamic_cast(*token.services_[ServiceApaas::kServiceType]); + const auto &apaas_service = dynamic_cast(*token.services_.find(ServiceApaas::kServiceType)->second); EXPECT_EQ("", apaas_service.room_uuid_); EXPECT_EQ("", apaas_service.user_uuid_); diff --git a/DynamicKey/AgoraDynamicKey/cpp/test/CMakeLists.txt b/DynamicKey/AgoraDynamicKey/cpp/test/CMakeLists.txt index b70108da..6ae4a3cf 100644 --- a/DynamicKey/AgoraDynamicKey/cpp/test/CMakeLists.txt +++ b/DynamicKey/AgoraDynamicKey/cpp/test/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 3.13) +cmake_minimum_required(VERSION 3.10) project(test) set(CMAKE_CXX_STANDARD 11) @@ -9,7 +9,7 @@ include_directories(..) include_directories(../../) link_directories(/usr/lib) -link_libraries(-lgtest -lz -lcrypto) +link_libraries(-lgtest -lz -lcrypto -lpthread) add_executable(test.exe AccessToken_test.cpp diff --git a/DynamicKey/AgoraDynamicKey/cpp/test/EducationTokenBuilder2_test.cpp b/DynamicKey/AgoraDynamicKey/cpp/test/EducationTokenBuilder2_test.cpp index dc1daac2..4f2dea4b 100644 --- a/DynamicKey/AgoraDynamicKey/cpp/test/EducationTokenBuilder2_test.cpp +++ b/DynamicKey/AgoraDynamicKey/cpp/test/EducationTokenBuilder2_test.cpp @@ -40,7 +40,7 @@ class EducationTokenBuilder2_test : public testing::Test { ASSERT_TRUE(token.services_.count(ServiceRtm::kServiceType)); ASSERT_TRUE(token.services_.count(ServiceChat::kServiceType)); - const auto &apaas_service = dynamic_cast(*token.services_[ServiceApaas::kServiceType]); + const auto &apaas_service = dynamic_cast(*token.services_.find(ServiceApaas::kServiceType)->second); EXPECT_EQ(room_uuid_, apaas_service.room_uuid_); EXPECT_EQ(user_id_, apaas_service.user_uuid_); @@ -49,13 +49,13 @@ class EducationTokenBuilder2_test : public testing::Test { ASSERT_TRUE(apaas_service.privileges_.count(ServiceApaas::kPrivilegeRoomUser)); EXPECT_EQ(expire_, apaas_service.privileges_.at(ServiceApaas::kPrivilegeRoomUser)); - const auto &rtm_service = dynamic_cast(*token.services_[ServiceRtm::kServiceType]); + const auto &rtm_service = dynamic_cast(*token.services_.find(ServiceRtm::kServiceType)->second); EXPECT_EQ(user_id_, rtm_service.user_id_); ASSERT_EQ(1, rtm_service.privileges_.size()); ASSERT_TRUE(rtm_service.privileges_.count(ServiceRtm::kPrivilegeLogin)); EXPECT_EQ(expire_, rtm_service.privileges_.at(ServiceRtm::kPrivilegeLogin)); - const auto &chat_service = dynamic_cast(*token.services_[ServiceChat::kServiceType]); + const auto &chat_service = dynamic_cast(*token.services_.find(ServiceChat::kServiceType)->second); EXPECT_EQ(chat_user_id_, chat_service.user_id_); ASSERT_EQ(1, chat_service.privileges_.size()); ASSERT_TRUE(chat_service.privileges_.count(ServiceChat::kPrivilegeUser)); @@ -73,7 +73,7 @@ class EducationTokenBuilder2_test : public testing::Test { ASSERT_EQ(1, token.services_.size()); ASSERT_TRUE(token.services_.count(ServiceApaas::kServiceType)); - const auto &apaas_service = dynamic_cast(*token.services_[ServiceApaas::kServiceType]); + const auto &apaas_service = dynamic_cast(*token.services_.find(ServiceApaas::kServiceType)->second); EXPECT_EQ("", apaas_service.room_uuid_); EXPECT_EQ(user_id_, apaas_service.user_uuid_); @@ -94,7 +94,7 @@ class EducationTokenBuilder2_test : public testing::Test { ASSERT_EQ(1, token.services_.size()); ASSERT_TRUE(token.services_.count(ServiceApaas::kServiceType)); - const auto &apaas_service = dynamic_cast(*token.services_[ServiceApaas::kServiceType]); + const auto &apaas_service = dynamic_cast(*token.services_.find(ServiceApaas::kServiceType)->second); EXPECT_EQ("", apaas_service.room_uuid_); EXPECT_EQ("", apaas_service.user_uuid_); From 357848d8eb4592db051dc6e032e724859c900c72 Mon Sep 17 00:00:00 2001 From: ZhangXiufang Date: Tue, 21 Jan 2025 08:43:56 +0000 Subject: [PATCH 2/2] Modify token007's PR suggestion --- .../AgoraDynamicKey/cpp/src/AccessToken2.h | 41 +++++++++++-------- .../cpp/test/AccessToken2_test.cpp | 9 +++- 2 files changed, 31 insertions(+), 19 deletions(-) diff --git a/DynamicKey/AgoraDynamicKey/cpp/src/AccessToken2.h b/DynamicKey/AgoraDynamicKey/cpp/src/AccessToken2.h index b61f6589..88650cfa 100644 --- a/DynamicKey/AgoraDynamicKey/cpp/src/AccessToken2.h +++ b/DynamicKey/AgoraDynamicKey/cpp/src/AccessToken2.h @@ -241,6 +241,14 @@ static const std::map kServiceCreator = { {ServiceApaas::kServiceType, ServiceCreator::New}, }; +enum TokenStatus { + kTokenVerifySuccess = 0, + kTokenVerifyFailed = -1, + kTokenInvalid = -2, + kTokenInvalidInfo = -3, + kTokenThrow = -4, +}; + class AccessToken2 { public: AccessToken2(const std::string &app_id = "", const std::string &app_certificate = "", uint32_t issue_ts = 0, uint32_t expire = 900) @@ -276,6 +284,7 @@ class AccessToken2 { try { auto buffer = Decompress(base64Decode(token.substr(VERSION_LENGTH))); + raw_token_buffer_ = buffer; Unpacker unpacker(buffer.data(), buffer.length()); unpacker >> signature_ >> app_id_ >> issue_ts_ >> expire_ >> salt_; UnpackServices(&unpacker); @@ -285,29 +294,26 @@ class AccessToken2 { return true; } - bool VerifySignature(std::string token, const std::string &app_certificate) { - if (token.substr(0, VERSION_LENGTH) != Version()) { - return false; + TokenStatus VerifySignature(const std::string &app_certificate) { + app_cert_ = app_certificate; + if (raw_token_buffer_.empty()) { + perror("invalid token, please unpack first by FromString()"); + return kTokenInvalid; + } else if (!BuildCheck()) { + return kTokenInvalidInfo; } - std::string signature; - std::string app_id; - uint32_t issue_ts; - uint32_t expire; - uint32_t salt; try { - auto buffer = Decompress(base64Decode(token.substr(VERSION_LENGTH))); - Unpacker unpacker(buffer.data(), buffer.length()); - unpacker >> signature >> app_id >> issue_ts >> expire >> salt; + std::string signature; + Unpacker unpacker(raw_token_buffer_.data(), raw_token_buffer_.length()); + unpacker >> signature; + auto signing = Signing(); - auto signing = HmacSign2(Pack(issue_ts), app_certificate, HMAC_SHA256_LENGTH); - signing = HmacSign2(Pack(salt), signing, HMAC_SHA256_LENGTH); - - auto signing_info = Pack(app_id) + Pack(issue_ts) + Pack(expire) + Pack(salt) + unpacker.pop_raw_string_to_end(); + auto signing_info = unpacker.pop_raw_string_to_end(); auto gen_signature = HmacSign2(signing, signing_info, HMAC_SHA256_LENGTH); - return signature == gen_signature; + return signature == gen_signature ? kTokenVerifySuccess : kTokenVerifyFailed; } catch (std::exception &e) { perror((std::string("VerifySignature error: ") + e.what()).c_str()); - return false; + return kTokenThrow; } } @@ -387,6 +393,7 @@ class AccessToken2 { std::string app_id_; std::string app_cert_; std::string signature_; + std::string raw_token_buffer_; std::multimap> services_; }; diff --git a/DynamicKey/AgoraDynamicKey/cpp/test/AccessToken2_test.cpp b/DynamicKey/AgoraDynamicKey/cpp/test/AccessToken2_test.cpp index 73896836..f8476ecf 100644 --- a/DynamicKey/AgoraDynamicKey/cpp/test/AccessToken2_test.cpp +++ b/DynamicKey/AgoraDynamicKey/cpp/test/AccessToken2_test.cpp @@ -359,8 +359,13 @@ class AccessToken2_test : public testing::Test { token.AddService(std::move(BuildRtmStreamServiceAsRtc(channel_name_, uid_, rtm_stream_expire))); std::string token_str = token.Build(); AccessToken2 token_parsed; + ASSERT_EQ(token_parsed.VerifySignature(app_certificate_), kTokenInvalid); ASSERT_TRUE(token_parsed.FromString(token_str)); - ASSERT_TRUE(token_parsed.VerifySignature(token_str, app_certificate_)); + ASSERT_EQ(token_parsed.VerifySignature(app_certificate_+"123"), kTokenInvalidInfo); + std::string err_cert = app_certificate_; + err_cert[0] = '1'; + ASSERT_EQ(token_parsed.VerifySignature(err_cert), kTokenVerifyFailed); + ASSERT_EQ(token_parsed.VerifySignature(app_certificate_), kTokenVerifySuccess); EXPECT_EQ(app_id_, token.app_id_); EXPECT_EQ(rtc_expire, token.expire_); @@ -407,7 +412,7 @@ class AccessToken2_test : public testing::Test { "RELgYjCwsjYxNDI3NjJqA5EJM4GUpSi0viS4tTi1jggqxwFrImAAIiLHc="; AccessToken2 token_parsed; ASSERT_TRUE(token_parsed.FromString(token_str)); - ASSERT_TRUE(token_parsed.VerifySignature(token_str, app_certificate_)); + ASSERT_EQ(token_parsed.VerifySignature(app_certificate_), kTokenVerifySuccess); EXPECT_EQ(token_parsed.app_id_, app_id_); EXPECT_EQ(token_parsed.expire_, expire_); EXPECT_EQ(token_parsed.GenerateSignature(app_certificate_), token_parsed.signature_);