diff --git a/include/jwt/impl/jwt.ipp b/include/jwt/impl/jwt.ipp index f1b9ec7..bfd36d1 100644 --- a/include/jwt/impl/jwt.ipp +++ b/include/jwt/impl/jwt.ipp @@ -85,19 +85,16 @@ inline void jwt_header::decode(const jwt::string_view enc_str, std::error_code& if (alg_ != algorithm::NONE) { auto itr = payload_.find("typ"); - if (itr == payload_.end()) { - ec = DecodeErrc::TypHeaderMiss; - return; + + if (itr != payload_.end()) { + const auto& typ = itr.value().get(); + if (strcasecmp(typ.c_str(), "JWT")) { + ec = DecodeErrc::TypMismatch; + return; + } + + typ_ = str_to_type(typ); } - - const auto& typ = itr.value().get(); - - if (strcasecmp(typ.c_str(), "JWT")) { - ec = DecodeErrc::TypMismatch; - return; - } - - typ_ = str_to_type(typ); } else { //TODO: } @@ -107,7 +104,8 @@ inline void jwt_header::decode(const jwt::string_view enc_str, std::error_code& auto ret = headers_.insert(it.key()); if (!ret.second) { ec = DecodeErrc::DuplClaims; - break; + //ATTN: Dont stop the decode here + //Not a hard error. } } diff --git a/include/jwt/jwt.hpp b/include/jwt/jwt.hpp index 1eb28a4..728dc5d 100644 --- a/include/jwt/jwt.hpp +++ b/include/jwt/jwt.hpp @@ -51,7 +51,8 @@ namespace jwt { */ enum class type { - JWT = 0, + NONE = 0, + JWT = 1, }; /** @@ -63,6 +64,7 @@ inline enum type str_to_type(const jwt::string_view typ) noexcept assert (typ.length() && "Empty type string"); if (!strcasecmp(typ.data(), "jwt")) return type::JWT; + else if(!strcasecmp(typ.data(), "none")) return type::NONE; throw std::runtime_error("Unknown token type"); @@ -410,6 +412,40 @@ public: // Exposed APIs overwrite); } + /** + * Remove the header from JWT. + * NOTE: Special handling for removing type field + * from header. The typ_ is set to NONE when removed. + */ + bool remove_header(const jwt::string_view hname) + { + if (!strcasecmp(hname.data(), "typ")) { + typ_ = type::NONE; + payload_.erase(hname.data()); + return true; + } + + auto itr = headers_.find(hname); + if (itr == std::end(headers_)) { + return false; + } + payload_.erase(hname.data()); + headers_.erase(hname.data()); + + return true; + } + + /** + * Checks if header with the given name + * is present or not. + */ + bool has_header(const jwt::string_view hname) + { + if (!strcasecmp(hname.data(), "typ")) return typ_ != type::NONE; + return headers_.find(hname) != std::end(headers_); + } + + /** * Get the URL safe base64 encoded string * of the header. diff --git a/tests/test_jwt_decode.cc b/tests/test_jwt_decode.cc index b84e9e9..1bb957f 100644 --- a/tests/test_jwt_decode.cc +++ b/tests/test_jwt_decode.cc @@ -156,6 +156,22 @@ TEST (DecodeTest, DecodeHS512) EXPECT_TRUE (obj.payload().has_claim_with_value("sub", "nothing much")); } +TEST (DecodeTest, TypHeaderMiss) +{ + using namespace jwt::params; + + const char* enc_str = + "eyJhbGciOiJIUzI1NiJ9." + "eyJleHAiOjE1MzM0NjE1NTMsImlhdCI6MTUxMzg2MjM3MSwiaWQiOiJhLWItYy1kLWUtZi0xLTItMyIsImlzcyI6ImFydW4ubXVyYWxpZGhhcmFuIiwic3ViIjoiYWRtaW4ifQ." + "pMWBLSWl1p4V958lfe_6ZhvgFMOQv9Eq5mlndVKFKkA"; + + std::error_code ec; + auto obj = jwt::decode(enc_str, algorithms({"none", "hs256"}), ec, verify(false)); + std::cout << "Decode header: " << obj.header() << std::endl; + + EXPECT_FALSE (ec); +} + int main(int argc, char* argv[]) { ::testing::InitGoogleTest(&argc, argv); return RUN_ALL_TESTS(); diff --git a/tests/test_jwt_encode.cc b/tests/test_jwt_encode.cc index a6bfcdd..f3c2976 100644 --- a/tests/test_jwt_encode.cc +++ b/tests/test_jwt_encode.cc @@ -25,6 +25,26 @@ TEST (EncodeTest, TestRemoveClaim) EXPECT_FALSE (obj.has_claim("sub")); } +TEST (EncodeTest, TestRemoveTypHeader) +{ + using namespace jwt::params; + + jwt::jwt_object obj{algorithm("hs256"), secret("secret")}; + + obj.add_claim("iss", "arun.muralidharan") + .add_claim("sub", "admin") + .add_claim("id", "a-b-c-d-e-f-1-2-3") + .add_claim("iat", 1513862371) + .add_claim("exp", std::chrono::system_clock::now()); + + EXPECT_TRUE (obj.header().has_header("typ")); + obj.header().remove_header("typ"); + EXPECT_FALSE (obj.header().has_header("typ")); + + std::cout << "Header: " << obj.header() << '\n'; + std::cout << "Signature: " << obj.signature() << '\n'; +} + TEST (EncodeTest, StrEncodeHS256_1) { using namespace jwt::params;