mirror of
https://github.com/arun11299/cpp-jwt.git
synced 2025-05-15 01:08:31 +00:00
Put verify under different function. Added new error codes for verification failures.
This commit is contained in:
parent
912e4b5ff9
commit
7a511c46fe
7 changed files with 204 additions and 30 deletions
|
@ -33,6 +33,17 @@ enum class DecodeErrc
|
||||||
DuplClaims,
|
DuplClaims,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
*/
|
||||||
|
enum class VerificationErrc
|
||||||
|
{
|
||||||
|
InvalidAlgorithm = 1,
|
||||||
|
TokenExpired,
|
||||||
|
InvalidIssuer,
|
||||||
|
InvalidAudience,
|
||||||
|
ImmatureSignature,
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*/
|
*/
|
||||||
std::error_code make_error_code(AlgorithmErrc err);
|
std::error_code make_error_code(AlgorithmErrc err);
|
||||||
|
@ -41,6 +52,10 @@ std::error_code make_error_code(AlgorithmErrc err);
|
||||||
*/
|
*/
|
||||||
std::error_code make_error_code(DecodeErrc err);
|
std::error_code make_error_code(DecodeErrc err);
|
||||||
|
|
||||||
|
/**
|
||||||
|
*/
|
||||||
|
std::error_code make_error_code(VerificationErrc err);
|
||||||
|
|
||||||
} // END namespace jwt
|
} // END namespace jwt
|
||||||
|
|
||||||
|
|
||||||
|
@ -55,6 +70,9 @@ namespace std
|
||||||
|
|
||||||
template <>
|
template <>
|
||||||
struct is_error_code_enum<jwt::DecodeErrc>: true_type {};
|
struct is_error_code_enum<jwt::DecodeErrc>: true_type {};
|
||||||
|
|
||||||
|
template <>
|
||||||
|
struct is_error_code_enum<jwt::VerificationErrc>: true_type {};
|
||||||
}
|
}
|
||||||
|
|
||||||
#include "jwt/impl/error_codes.ipp"
|
#include "jwt/impl/error_codes.ipp"
|
||||||
|
|
|
@ -59,11 +59,42 @@ struct DecodeErrorCategory: std::error_category
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
*/
|
||||||
|
struct VerificationErrorCategory: std::error_category
|
||||||
|
{
|
||||||
|
const char* name() const noexcept override
|
||||||
|
{
|
||||||
|
return "verification";
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string message(int ev) const override
|
||||||
|
{
|
||||||
|
switch (static_cast<VerificationErrc>(ev))
|
||||||
|
{
|
||||||
|
case VerificationErrc::InvalidAlgorithm:
|
||||||
|
return "invalid algorithm";
|
||||||
|
case VerificationErrc::TokenExpired:
|
||||||
|
return "token expired";
|
||||||
|
case VerificationErrc::InvalidIssuer:
|
||||||
|
return "invalid issuer";
|
||||||
|
case VerificationErrc::InvalidAudience:
|
||||||
|
return "invalid audience";
|
||||||
|
case VerificationErrc::ImmatureSignature:
|
||||||
|
return "immature signature";
|
||||||
|
};
|
||||||
|
|
||||||
|
assert (0 && "Code not reached");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
// Create global object for the error categories
|
// Create global object for the error categories
|
||||||
const AlgorithmErrCategory theAlgorithmErrCategory {};
|
const AlgorithmErrCategory theAlgorithmErrCategory {};
|
||||||
|
|
||||||
const DecodeErrorCategory theDecodeErrorCategory {};
|
const DecodeErrorCategory theDecodeErrorCategory {};
|
||||||
|
|
||||||
|
const VerificationErrorCategory theVerificationErrorCategory {};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -78,6 +109,10 @@ std::error_code make_error_code(DecodeErrc err)
|
||||||
return { static_cast<int>(err), theDecodeErrorCategory };
|
return { static_cast<int>(err), theDecodeErrorCategory };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::error_code make_error_code(VerificationErrc err)
|
||||||
|
{
|
||||||
|
return { static_cast<int>(err), theVerificationErrorCategory };
|
||||||
|
}
|
||||||
|
|
||||||
} // END namespace jwt
|
} // END namespace jwt
|
||||||
|
|
||||||
|
|
|
@ -330,6 +330,71 @@ std::string jwt_object::signature() const
|
||||||
return jws.encode(header_, payload_);
|
return jws.encode(header_, payload_);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <typename Params, typename SequenceT>
|
||||||
|
std::error_code jwt_object::verify(
|
||||||
|
const Params& dparams,
|
||||||
|
const params::detail::algorithms_param<SequenceT>& algos) const
|
||||||
|
{
|
||||||
|
std::error_code ec{};
|
||||||
|
|
||||||
|
//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) == header().algo();
|
||||||
|
});
|
||||||
|
|
||||||
|
if (fitr == algos.get().end()) {
|
||||||
|
ec = VerificationErrc::InvalidAlgorithm;
|
||||||
|
return ec;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Check for the expiry timings
|
||||||
|
if (has_claim(registered_claims::expiration)) {
|
||||||
|
auto curr_time =
|
||||||
|
std::chrono::duration_cast<
|
||||||
|
std::chrono::seconds>(std::chrono::system_clock::now().time_since_epoch()).count();
|
||||||
|
|
||||||
|
auto p_exp = payload()
|
||||||
|
.get_claim_value<uint64_t>(registered_claims::expiration);
|
||||||
|
|
||||||
|
if (p_exp < (curr_time + dparams.leeway)) {
|
||||||
|
ec = VerificationErrc::TokenExpired;
|
||||||
|
return ec;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//Check for issuer
|
||||||
|
if (dparams.has_issuer &&
|
||||||
|
has_claim(registered_claims::issuer))
|
||||||
|
{
|
||||||
|
jwt::string_view p_issuer = payload()
|
||||||
|
.get_claim_value<std::string>(registered_claims::issuer);
|
||||||
|
|
||||||
|
if (p_issuer.data() != dparams.issuer) {
|
||||||
|
ec = VerificationErrc::InvalidIssuer;
|
||||||
|
return ec;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//Check for audience
|
||||||
|
if (dparams.has_aud &&
|
||||||
|
has_claim(registered_claims::audience))
|
||||||
|
{
|
||||||
|
jwt::string_view p_aud = payload()
|
||||||
|
.get_claim_value<std::string>(registered_claims::audience);
|
||||||
|
|
||||||
|
if (p_aud.data() != dparams.aud) {
|
||||||
|
ec = VerificationErrc::InvalidAudience;
|
||||||
|
return ec;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ec;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
std::array<string_view, 3>
|
std::array<string_view, 3>
|
||||||
jwt_object::three_parts(const string_view enc_str)
|
jwt_object::three_parts(const string_view enc_str)
|
||||||
|
@ -349,7 +414,7 @@ jwt_object::three_parts(const string_view enc_str)
|
||||||
result[1] = string_view{&enc_str[fpos + 1], spos - fpos - 1};
|
result[1] = string_view{&enc_str[fpos + 1], spos - fpos - 1};
|
||||||
|
|
||||||
if (spos != enc_str.length()) {
|
if (spos != enc_str.length()) {
|
||||||
result[2] = string_view{&enc_str[spos + 1], enc_str.length() - spos};
|
result[2] = string_view{&enc_str[spos + 1], enc_str.length() - spos - 1};
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
|
@ -376,6 +441,23 @@ void set_decode_params(DecodeParams& dparams, params::detail::verify_param v, Re
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <typename DecodeParams, typename... Rest>
|
||||||
|
void set_decode_params(DecodeParams& dparams, params::detail::issuer_param i, Rest&&... args)
|
||||||
|
{
|
||||||
|
dparams.issuer = std::move(i).get();
|
||||||
|
dparams.has_issuer = true;
|
||||||
|
set_decode_params(dparams, std::forward<Rest>(args)...);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename DecodeParams, typename... Rest>
|
||||||
|
void set_decode_params(DecodeParams& dparams, params::detail::audience_param a, Rest&&... args)
|
||||||
|
{
|
||||||
|
dparams.aud = std::move(a).get();
|
||||||
|
dparams.has_aud = true;
|
||||||
|
set_decode_params(dparams, std::forward<Rest>(args)...);
|
||||||
|
}
|
||||||
|
|
||||||
template <typename DecodeParams>
|
template <typename DecodeParams>
|
||||||
void set_decode_params(DecodeParams& dparams)
|
void set_decode_params(DecodeParams& dparams)
|
||||||
{
|
{
|
||||||
|
@ -400,6 +482,14 @@ jwt_object decode(const string_view enc_str,
|
||||||
bool verify = true;
|
bool verify = true;
|
||||||
/// Leeway parameter. Defaulted to zero seconds.
|
/// Leeway parameter. Defaulted to zero seconds.
|
||||||
uint32_t leeway = 0;
|
uint32_t leeway = 0;
|
||||||
|
///The issuer
|
||||||
|
//TODO: optional type
|
||||||
|
bool has_issuer = false;
|
||||||
|
std::string issuer;
|
||||||
|
///The audience
|
||||||
|
//TODO: optional type
|
||||||
|
bool has_aud = false;
|
||||||
|
std::string aud;
|
||||||
};
|
};
|
||||||
|
|
||||||
decode_params dparams{};
|
decode_params dparams{};
|
||||||
|
@ -414,31 +504,8 @@ jwt_object decode(const string_view enc_str,
|
||||||
//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) {
|
if (dparams.verify) {
|
||||||
//Verify if the algorithm set in the header
|
std::error_code ec = obj.verify(dparams, algos);
|
||||||
//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>();
|
|
||||||
|
|
||||||
if (p_exp < (curr_time + dparams.leeway)) {
|
|
||||||
throw VerificationError("Token expired");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
jwt_signature jsign{key};
|
jwt_signature jsign{key};
|
||||||
|
|
|
@ -358,16 +358,18 @@ public: // Exposed APIs
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*/
|
*/
|
||||||
|
template <typename T>
|
||||||
decltype(auto) get_claim_value(const string_view cname) const
|
decltype(auto) get_claim_value(const string_view cname) const
|
||||||
{
|
{
|
||||||
return payload_[cname.data()];
|
return payload_[cname.data()].get<T>();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*/
|
*/
|
||||||
|
template <typename T>
|
||||||
decltype(auto) get_claim_value(enum registered_claims cname) const
|
decltype(auto) get_claim_value(enum registered_claims cname) const
|
||||||
{
|
{
|
||||||
return get_claim_value(reg_claims_to_str(cname));
|
return get_claim_value<T>(reg_claims_to_str(cname));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -648,10 +650,31 @@ public: // Exposed APIs
|
||||||
return remove_claim(reg_claims_to_str(cname));
|
return remove_claim(reg_claims_to_str(cname));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*/
|
||||||
|
bool has_claim(const string_view cname) const noexcept
|
||||||
|
{
|
||||||
|
return payload().has_claim(cname);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*/
|
||||||
|
bool has_claim(enum registered_claims cname) const noexcept
|
||||||
|
{
|
||||||
|
return payload().has_claim(cname);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*/
|
*/
|
||||||
std::string signature() const;
|
std::string signature() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*/
|
||||||
|
template <typename Params, typename SequenceT>
|
||||||
|
std::error_code verify(
|
||||||
|
const Params& dparams,
|
||||||
|
const params::detail::algorithms_param<SequenceT>& algos) const;
|
||||||
|
|
||||||
private: // private APIs
|
private: // private APIs
|
||||||
/**
|
/**
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
#define CPP_JWT_PARAMETERS_HPP
|
#define CPP_JWT_PARAMETERS_HPP
|
||||||
|
|
||||||
#include <map>
|
#include <map>
|
||||||
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
|
@ -143,6 +144,34 @@ struct leeway_param
|
||||||
uint32_t leeway_;
|
uint32_t leeway_;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
*/
|
||||||
|
struct audience_param
|
||||||
|
{
|
||||||
|
audience_param(std::string aud)
|
||||||
|
: aud_(std::move(aud))
|
||||||
|
{}
|
||||||
|
|
||||||
|
const std::string& get() const& noexcept { return aud_; }
|
||||||
|
std::string get() && noexcept { return aud_; }
|
||||||
|
|
||||||
|
std::string aud_;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
*/
|
||||||
|
struct issuer_param
|
||||||
|
{
|
||||||
|
issuer_param(std::string iss)
|
||||||
|
: iss_(std::move(iss))
|
||||||
|
{}
|
||||||
|
|
||||||
|
const std::string& get() const& noexcept { return iss_; }
|
||||||
|
std::string get() && noexcept { return iss_; }
|
||||||
|
|
||||||
|
std::string iss_;
|
||||||
|
};
|
||||||
|
|
||||||
} // END namespace detail
|
} // END namespace detail
|
||||||
|
|
||||||
// Useful typedef
|
// Useful typedef
|
||||||
|
|
Binary file not shown.
|
@ -79,14 +79,16 @@ MIGkAgEBBDBeLCgapjZmvTatMHaYX3A02+0Ys3Tr8kda+E9DFnmCSiCOEig519fT
|
||||||
;
|
;
|
||||||
|
|
||||||
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;
|
std::cout << "Get claim value for exp: " <<
|
||||||
|
obj.payload().get_claim_value<uint64_t>("exp") << std::endl;
|
||||||
|
|
||||||
sleep(4);
|
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;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue