JWT veririfcation APIs

This commit is contained in:
Arun M 2017-12-13 23:57:25 +05:30
parent 7a7353a9ef
commit 6f495c2c16
6 changed files with 152 additions and 14 deletions

View file

@ -134,7 +134,12 @@ struct is_sequence_concept: std::false_type
template <typename T> template <typename T>
struct is_sequence_concept<T, struct is_sequence_concept<T,
void_t< void_t<
std::enable_if_t<std::is_array<std::decay_t<T>>::value> std::enable_if_t<std::is_array<std::decay_t<T>>::value>,
std::enable_if_t<
std::is_constructible<jwt::string_view,
std::remove_reference_t<decltype(*std::begin(std::declval<T&>()))>>::value
>
> >
>: std::true_type >: std::true_type
{ {
@ -147,7 +152,10 @@ struct is_sequence_concept<T,
std::is_base_of< std::is_base_of<
std::forward_iterator_tag, std::forward_iterator_tag,
typename std::remove_reference_t<T>::iterator::iterator_category typename std::remove_reference_t<T>::iterator::iterator_category
>::value >::value>,
std::enable_if_t<
std::is_constructible<jwt::string_view, typename std::remove_reference_t<T>::value_type>::value
>, >,
decltype( decltype(

View file

@ -2,6 +2,7 @@
#define CPP_JWT_EXCEPTIONS_HPP #define CPP_JWT_EXCEPTIONS_HPP
#include <new> #include <new>
#include <string>
namespace jwt { 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 } // END namespace jwt

View file

@ -2,6 +2,7 @@
#define JWT_IPP #define JWT_IPP
#include "jwt/detail/meta.hpp" #include "jwt/detail/meta.hpp"
#include <algorithm>
namespace jwt { namespace jwt {
@ -100,6 +101,9 @@ void jwt_payload::decode(const string_view enc_str, std::error_code& ec) noexcep
ec = DecodeErrc::JsonParseError; ec = DecodeErrc::JsonParseError;
return; return;
} }
//validate the fields
//TODO:
return; return;
} }
@ -140,15 +144,12 @@ std::string jwt_signature::encode(const jwt_header& header,
return jwt_msg; 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 hdr_pld_sign,
const string_view jwt_sign) const string_view jwt_sign)
{ {
//TODO: is bool the right choice ?
verify_func_t verify_fn = get_verify_algorithm_impl(header); verify_func_t verify_fn = get_verify_algorithm_impl(header);
verify_fn(key_, hdr_pld_sign, jwt_sign); return verify_fn(key_, hdr_pld_sign, jwt_sign);
return true;
} }
@ -399,19 +400,57 @@ jwt_object decode(const string_view enc_str,
set_decode_params(dparams, std::forward<Args>(args)...); set_decode_params(dparams, std::forward<Args>(args)...);
jwt_object obj; jwt_object obj;
auto parts = jwt_object::three_parts(enc_str); auto parts = jwt_object::three_parts(enc_str);
//throws decode error //throws decode error
obj.header(jwt_header{parts[0]}); obj.header(jwt_header{parts[0]});
//throws decode error //throws decode error
obj.payload(jwt_payload{parts[1]}); 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<uint64_t>();
std::cout << curr_time << " :: " << p_exp << std::endl;
if (p_exp < curr_time) {
throw VerificationError("Token expired");
}
}
}
jwt_signature jsign{key}; jwt_signature jsign{key};
// Length of the encoded header and payload only. // Length of the encoded header and payload only.
// Addition of '1' to account for the '.' character. // Addition of '1' to account for the '.' character.
auto l = parts[0].length() + 1 + parts[1].length(); 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; return obj;
} }

View file

@ -306,6 +306,7 @@ public: // Exposed APIs
{ {
// Duplicate claim names not allowed // Duplicate claim names not allowed
// if overwrite flag is set to true. // if overwrite flag is set to true.
std::cout << "Adding claim: " << claim_names_.size() << std::endl;
auto itr = claim_names_.find(cname); auto itr = claim_names_.find(cname);
if (itr != claim_names_.end() && !overwrite) { if (itr != claim_names_.end() && !overwrite) {
return false; return false;
@ -327,10 +328,49 @@ public: // Exposed APIs
return add_claim( return add_claim(
cname, cname,
std::chrono::duration_cast< std::chrono::duration_cast<
std::chrono::seconds>(tp.time_since_epoch()).count() std::chrono::seconds>(tp.time_since_epoch()).count(),
overwrite
); );
} }
/**
*/
template <typename T>
bool add_claim(enum registered_claims cname, T&& cvalue, bool overwrite=false)
{
return add_claim(
reg_claims_to_str(cname),
std::forward<T>(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) 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); return claim_names_.count(cname);
} }
/**
*/
bool has_claim(enum registered_claims cname) const noexcept
{
return has_claim(reg_claims_to_str(cname));
}
/** /**
*/ */
template <typename T> template <typename T>
@ -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 hdr_pld_sign,
const string_view jwt_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); jwt_object& add_claim(const string_view name, system_time_t time_point);
/**
*/
template <typename T>
jwt_object& add_claim(enum registered_claims cname, T&& value)
{
return add_claim(reg_claims_to_str(cname), std::forward<T>(value));
}
/** /**
*/ */
jwt_object& remove_claim(const string_view name); 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; std::string signature() const;

Binary file not shown.

View file

@ -2,6 +2,7 @@
#include <map> #include <map>
#include <string> #include <string>
#include <chrono> #include <chrono>
#include <ctime>
#include <unordered_map> #include <unordered_map>
#include "jwt/jwt.hpp" #include "jwt/jwt.hpp"
@ -74,15 +75,18 @@ MIGkAgEBBDBeLCgapjZmvTatMHaYX3A02+0Ys3Tr8kda+E9DFnmCSiCOEig519fT
.add_claim("where", "airport") .add_claim("where", "airport")
.add_claim("time_str", "8:18pm 24 Nov 2017") .add_claim("time_str", "8:18pm 24 Nov 2017")
.add_claim("id", 1) .add_claim("id", 1)
.add_claim("exp", std::chrono::system_clock::now())
; ;
std::cout << "pem sign " << obj.signature() << std::endl; 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"})); auto dec_obj = jwt::decode(obj.signature(), pub_key, algorithms({"es256"}));
std::cout << dec_obj.payload() << std::endl; std::cout << dec_obj.payload() << std::endl;
} }
int main() { int main() {
basic_jwt_object_test(); //basic_jwt_object_test();
jwt_object_pem_test(); jwt_object_pem_test();
return 0; return 0;
} }