Put verify under different function. Added new error codes for verification failures.

This commit is contained in:
Arun M 2017-12-16 16:39:52 +05:30
parent 912e4b5ff9
commit 7a511c46fe
7 changed files with 204 additions and 30 deletions

View file

@ -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"

View file

@ -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

View file

@ -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};

View file

@ -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
/** /**
*/ */

View file

@ -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.

View file

@ -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;
} }