diff --git a/include/jwt/impl/jwt.ipp b/include/jwt/impl/jwt.ipp index 2613b19..0e98bb6 100644 --- a/include/jwt/impl/jwt.ipp +++ b/include/jwt/impl/jwt.ipp @@ -211,6 +211,9 @@ template void jwt_object::set_parameters( params::detail::payload_param&& payload, Rest&&... rargs) { + for (const auto& elem : payload.get()) { + payload_.add_claim(std::move(elem.first), std::move(elem.second)); + } set_parameters(std::forward(rargs)...); } @@ -218,6 +221,7 @@ template void jwt_object::set_parameters( params::detail::secret_param secret, Rest&&... rargs) { + secret_.assign(secret.get().data(), secret.get().length()); set_parameters(std::forward(rargs)...); } @@ -225,6 +229,7 @@ template void jwt_object::set_parameters( params::detail::headers_param&& header, Rest&&... rargs) { + //TODO: add kid support set_parameters(std::forward(rargs)...); } @@ -235,37 +240,72 @@ void jwt_object::set_parameters() } template -jwt_payload& jwt_object::add_payload(const std::string& name, T&& value) +jwt_payload& jwt_object::add_claim(const std::string& name, T&& value) { payload_.add_claim(name, std::forward(value)); return payload_; } - -//==================================================================== - -void jwt_decode(const string_view encoded_str, const string_view key, bool validate) +jwt_payload& jwt_object::remove_claim(const std::string& name) { - //TODO: implement error_code - size_t fpos = encoded_str.find_first_of('.'); + payload_.remove_claim(name); + return payload_; +} + +std::string jwt_object::signature() const +{ + jwt_signature jws{secret_}; + + return jws.encode(header_, payload_); +} + + +std::array +jwt_object::three_parts(const string_view enc_str) +{ + std::array result; + + size_t fpos = enc_str.find_first_of('.'); assert (fpos != string_view::npos); - string_view head{&encoded_str[0], fpos}; - jwt_header hdr; - hdr.decode(head); + result[0] = string_view{&enc_str[0], fpos}; - size_t spos = encoded_str.find_first_of('.', fpos + 1); + size_t spos = enc_str.find_first_of('.', fpos + 1); if (spos == string_view::npos) { //TODO: Check for none algorithm } - string_view body{&encoded_str[fpos + 1], spos - fpos - 1}; - //Json objects or claims get set in the decode - jwt_payload pld; - pld.decode(body); + result[1] = string_view{&enc_str[fpos + 1], spos - fpos - 1}; + + size_t tpos = enc_str.find_first_of('.', spos + 1); + + if (tpos != string_view::npos) { + result[2] = string_view{&enc_str[tpos + 1], tpos - spos - 1}; + } + + return result; +} + + +//==================================================================== + +jwt_object jwt_decode(const string_view encoded_str, const string_view key, bool validate) +{ + //TODO: implement error_code + jwt_object jobj; + + auto parts = jwt_object::three_parts(encoded_str); + + jobj.header(jwt_header{parts[0]}); + jobj.payload(jwt_payload{parts[1]}); jwt_signature jsign{key}; - jsign.verify(hdr, encoded_str.substr(0, spos), encoded_str); + //length of the encoded header and payload only. + //Addition of '1' to account for the '.' character. + auto l = parts[0].length() + 1 + parts[1].length(); + jsign.verify(jobj.header(), encoded_str.substr(0, l), encoded_str); + + return jobj; } } // END namespace jwt diff --git a/include/jwt/jwt.hpp b/include/jwt/jwt.hpp index cebf2ed..0c90549 100644 --- a/include/jwt/jwt.hpp +++ b/include/jwt/jwt.hpp @@ -1,11 +1,12 @@ #ifndef JWT_HPP #define JWT_HPP -#include -#include #include +#include #include #include +#include +#include #include "jwt/base64.hpp" #include "jwt/algorithm.hpp" @@ -233,6 +234,15 @@ public: // 'tors { } + /** + * Construct the header from an encoded string. + * TODO: Throw an exception in case of error + */ + jwt_header(const string_view enc_str) + { + this->decode(enc_str); + } + /// Default Copy and assignment jwt_header(const jwt_header&) = default; jwt_header& operator=(const jwt_header&) = default; @@ -312,10 +322,19 @@ struct jwt_payload: write_interface , base64_enc_dec { public: // 'tors - /*! + /** */ jwt_payload() = default; + /** + * Construct the payload from an encoded string. + * TODO: Throw an exception in case of error. + */ + jwt_payload(const string_view enc_str) + { + this->decode(enc_str); + } + /// Default copy and assignment operations jwt_payload(const jwt_payload&) = default; jwt_payload& operator=(const jwt_payload&) = default; @@ -323,7 +342,7 @@ public: // 'tors ~jwt_payload() = default; public: // Exposed APIs - /*! + /** */ template bool add_claim(const std::string& cname, T&& cvalue, bool overwrite=false) @@ -346,14 +365,27 @@ public: // Exposed APIs return true; } - /*! + /** + */ + bool remove_claim(const std::string& cname) + { + auto itr = claim_names_.find(cname); + if (itr == claim_names_.end()) return false; + + claim_names_.erase(itr); + payload_.erase(cname.c_str()); + + return true; + } + + /** */ bool has_claim(const std::string& cname) const noexcept { return claim_names_.count(cname); } - /*! + /** */ template bool has_claim_with_value(const std::string& cname, T&& cvalue) const @@ -364,19 +396,19 @@ public: // Exposed APIs return (cvalue == payload_[cname]); } - /*! + /** */ std::string encode(bool pprint = false) { return base64_encode(pprint); } - /*! + /** */ //TODO: what about error_code ? void decode(const string_view enc_str); - /*! + /** */ const json_t& create_json_obj() const { @@ -384,14 +416,35 @@ public: // Exposed APIs } private: - /*! + /** */ - struct case_compare { + struct case_compare + { + using is_transparent = std::true_type; + bool operator()(const std::string& lhs, const std::string& rhs) const { int ret = strcasecmp(lhs.c_str(), rhs.c_str()); return (ret < 0); } + + bool operator()(const string_view lhs, const string_view rhs) const + { + int ret = strcasecmp(lhs.data(), rhs.data()); + return (ret < 0); + } + + bool operator()(const std::string& lhs, const string_view rhs) const + { + int ret = strcasecmp(lhs.data(), rhs.data()); + return (ret < 0); + } + + bool operator()(const string_view lhs, const std::string& rhs) const + { + int ret = strcasecmp(lhs.data(), rhs.data()); + return (ret < 0); + } }; /// JSON object containing payload @@ -449,7 +502,7 @@ private: // Data members; }; -/*! +/** */ class jwt_object { @@ -463,6 +516,12 @@ public: // 'tors template jwt_object(Args&&... args); +public: // Exposed static APIs + /** + */ + static std::array + three_parts(const string_view enc_str); + public: // Exposed APIs /** */ @@ -478,6 +537,34 @@ public: // Exposed APIs return payload_; } + /** + */ + void payload(const jwt_payload& p) + { + payload_ = p; + } + + /** + */ + void payload(jwt_payload&& p) + { + payload_ = std::move(p); + } + + /** + */ + void header(const jwt_header& h) + { + header_ = h; + } + + /** + */ + void header(jwt_header&& h) + { + header_ = std::move(h); + } + /** */ jwt_header& header() noexcept @@ -495,7 +582,15 @@ public: // Exposed APIs /** */ template - jwt_payload& add_payload(const std::string& name, T&& value); + jwt_payload& add_claim(const std::string& name, T&& value); + + /** + */ + jwt_payload& remove_claim(const std::string& name); + + /** + */ + std::string signature() const; private: // private APIs /** @@ -536,7 +631,7 @@ private: // Data Members /*! */ -void jwt_decode(const string_view encoded_str, const string_view key, bool validate=true); +jwt_object jwt_decode(const string_view encoded_str, const string_view key, bool validate=true); } // END namespace jwt diff --git a/include/jwt/test/test_jwt_object b/include/jwt/test/test_jwt_object index aa50cbf..d228898 100755 Binary files a/include/jwt/test/test_jwt_object and b/include/jwt/test/test_jwt_object differ