diff --git a/include/jwt/detail/meta.hpp b/include/jwt/detail/meta.hpp index 10f71c7..8f19d75 100644 --- a/include/jwt/detail/meta.hpp +++ b/include/jwt/detail/meta.hpp @@ -134,7 +134,12 @@ struct is_sequence_concept: std::false_type template struct is_sequence_concept>::value> + std::enable_if_t>::value>, + + std::enable_if_t< + std::is_constructible()))>>::value + > > >: std::true_type { @@ -147,8 +152,11 @@ struct is_sequence_concept::iterator::iterator_category - >::value - >, + >::value>, + + std::enable_if_t< + std::is_constructible::value_type>::value + >, decltype( std::declval().begin(), diff --git a/include/jwt/exceptions.hpp b/include/jwt/exceptions.hpp index 3c5af44..a614f15 100644 --- a/include/jwt/exceptions.hpp +++ b/include/jwt/exceptions.hpp @@ -2,6 +2,7 @@ #define CPP_JWT_EXCEPTIONS_HPP #include +#include namespace jwt { @@ -42,6 +43,18 @@ public: } }; +/** + */ +class VerificationError final: public std::runtime_error +{ +public: + /** + */ + VerificationError(std::string msg) + : std::runtime_error(std::move(msg)) + { + } +}; } // END namespace jwt diff --git a/include/jwt/impl/jwt.ipp b/include/jwt/impl/jwt.ipp index ea1095e..bf6a260 100644 --- a/include/jwt/impl/jwt.ipp +++ b/include/jwt/impl/jwt.ipp @@ -2,6 +2,7 @@ #define JWT_IPP #include "jwt/detail/meta.hpp" +#include namespace jwt { @@ -100,6 +101,9 @@ void jwt_payload::decode(const string_view enc_str, std::error_code& ec) noexcep ec = DecodeErrc::JsonParseError; return; } + + //validate the fields + //TODO: return; } @@ -140,15 +144,12 @@ std::string jwt_signature::encode(const jwt_header& header, return jwt_msg; } -bool jwt_signature::verify(const jwt_header& header, +verify_result_t jwt_signature::verify(const jwt_header& header, const string_view hdr_pld_sign, const string_view jwt_sign) { - //TODO: is bool the right choice ? verify_func_t verify_fn = get_verify_algorithm_impl(header); - verify_fn(key_, hdr_pld_sign, jwt_sign); - - return true; + return verify_fn(key_, hdr_pld_sign, jwt_sign); } @@ -399,19 +400,57 @@ jwt_object decode(const string_view enc_str, set_decode_params(dparams, std::forward(args)...); jwt_object obj; - auto parts = jwt_object::three_parts(enc_str); + //throws decode error obj.header(jwt_header{parts[0]}); + //throws decode error obj.payload(jwt_payload{parts[1]}); + //TODO: Should be part of jwt_object::verify + if (dparams.verify) { + //Verify if the algorithm set in the header + //is any of the one expected by the client. + auto fitr = std::find_if(algos.get().begin(), algos.get().end(), + [&](const auto& elem) { + return jwt::str_to_alg(elem) == obj.header().algo(); + }); + + if (fitr == algos.get().end()) { + throw VerificationError("Provided algorithms do not match with header"); + } + + //Check for the expiry timings + if (obj.payload().has_claim("exp")) { + auto curr_time = std::chrono::duration_cast< + std::chrono::seconds>(std::chrono::system_clock::now().time_since_epoch()).count(); + auto p_exp = obj.payload() + .get_claim_value(registered_claims::expiration) + .get(); + + std::cout << curr_time << " :: " << p_exp << std::endl; + + if (p_exp < curr_time) { + throw VerificationError("Token expired"); + } + } + } + jwt_signature jsign{key}; // 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(); - auto res = jsign.verify(obj.header(), enc_str.substr(0, l), parts[2]); + + verify_result_t res = jsign.verify(obj.header(), enc_str.substr(0, l), parts[2]); + if (res.second) { + throw VerificationError(res.second.message()); + } + + if (!res.first) { + throw VerificationError("Verification failed due to unknown reason"); + } return obj; } diff --git a/include/jwt/jwt.hpp b/include/jwt/jwt.hpp index 16ebcae..689ddfb 100644 --- a/include/jwt/jwt.hpp +++ b/include/jwt/jwt.hpp @@ -306,6 +306,7 @@ public: // Exposed APIs { // Duplicate claim names not allowed // if overwrite flag is set to true. + std::cout << "Adding claim: " << claim_names_.size() << std::endl; auto itr = claim_names_.find(cname); if (itr != claim_names_.end() && !overwrite) { return false; @@ -327,10 +328,49 @@ public: // Exposed APIs return add_claim( cname, std::chrono::duration_cast< - std::chrono::seconds>(tp.time_since_epoch()).count() + std::chrono::seconds>(tp.time_since_epoch()).count(), + overwrite ); } + /** + */ + template + bool add_claim(enum registered_claims cname, T&& cvalue, bool overwrite=false) + { + return add_claim( + reg_claims_to_str(cname), + std::forward(cvalue), + overwrite + ); + } + + /** + */ + bool add_claim(enum registered_claims cname, system_time_t tp, bool overwrite=false) + { + return add_claim( + reg_claims_to_str(cname), + std::chrono::duration_cast< + std::chrono::seconds>(tp.time_since_epoch()).count(), + overwrite + ); + } + + /** + */ + decltype(auto) get_claim_value(const string_view cname) const + { + return payload_[cname.data()]; + } + + /** + */ + decltype(auto) get_claim_value(enum registered_claims cname) const + { + return get_claim_value(reg_claims_to_str(cname)); + } + /** */ bool remove_claim(const string_view cname) @@ -346,11 +386,30 @@ public: // Exposed APIs /** */ - bool has_claim(const std::string& cname) const noexcept + bool remove_claim(enum registered_claims cname) { + return remove_claim(reg_claims_to_str(cname)); + } + + /** + */ + //TODO: Not all libc++ version agrees with this + //because count() is not made const for is_transparent + //based overload + bool has_claim(const string_view cname) const noexcept + { + std::cout << "CSZ: " << claim_names_.size() << std::endl; + for (auto c : claim_names_) std::cout << "Claim: " << c << std::endl; return claim_names_.count(cname); } + /** + */ + bool has_claim(enum registered_claims cname) const noexcept + { + return has_claim(reg_claims_to_str(cname)); + } + /** */ template @@ -451,7 +510,7 @@ public: // Exposed APIs /*! */ - bool verify(const jwt_header& header, + verify_result_t verify(const jwt_header& header, const string_view hdr_pld_sign, const string_view jwt_sign); @@ -573,10 +632,25 @@ public: // Exposed APIs */ jwt_object& add_claim(const string_view name, system_time_t time_point); + /** + */ + template + jwt_object& add_claim(enum registered_claims cname, T&& value) + { + return add_claim(reg_claims_to_str(cname), std::forward(value)); + } + /** */ jwt_object& remove_claim(const string_view name); + /** + */ + jwt_object& remove_claim(enum registered_claims cname) + { + return remove_claim(reg_claims_to_str(cname)); + } + /** */ std::string signature() const; diff --git a/include/jwt/test/test_jwt_object b/include/jwt/test/test_jwt_object index ffbb701..b970955 100755 Binary files a/include/jwt/test/test_jwt_object and b/include/jwt/test/test_jwt_object differ diff --git a/include/jwt/test/test_jwt_object.cc b/include/jwt/test/test_jwt_object.cc index 50c1032..69deda1 100644 --- a/include/jwt/test/test_jwt_object.cc +++ b/include/jwt/test/test_jwt_object.cc @@ -2,6 +2,7 @@ #include #include #include +#include #include #include "jwt/jwt.hpp" @@ -74,15 +75,18 @@ MIGkAgEBBDBeLCgapjZmvTatMHaYX3A02+0Ys3Tr8kda+E9DFnmCSiCOEig519fT .add_claim("where", "airport") .add_claim("time_str", "8:18pm 24 Nov 2017") .add_claim("id", 1) + .add_claim("exp", std::chrono::system_clock::now()) ; std::cout << "pem sign " << obj.signature() << std::endl; + std::cout << "Get claim value for exp: " << obj.payload().get_claim_value("exp") << std::endl; + sleep(4); auto dec_obj = jwt::decode(obj.signature(), pub_key, algorithms({"es256"})); std::cout << dec_obj.payload() << std::endl; } int main() { - basic_jwt_object_test(); + //basic_jwt_object_test(); jwt_object_pem_test(); return 0; }