mirror of
https://github.com/arun11299/cpp-jwt.git
synced 2025-05-14 16:58:34 +00:00
JWT header impl
This commit is contained in:
parent
063a0af131
commit
3e867d77f1
13 changed files with 358 additions and 20 deletions
|
@ -36,41 +36,41 @@ std::string base64_encode(const char* in, size_t len)
|
|||
std::string result;
|
||||
result.resize(128);
|
||||
|
||||
constexpr static const EMap bmap{};
|
||||
constexpr static const EMap emap{};
|
||||
|
||||
int i = 0;
|
||||
|
||||
int j = 0;
|
||||
for (; i < len - 2; i += 3) {
|
||||
auto first = in[i];
|
||||
auto second = in[i+1];
|
||||
auto third = in[i+2];
|
||||
auto& first = in[i];
|
||||
auto& second = in[i+1];
|
||||
auto& third = in[i+2];
|
||||
|
||||
result[i] = bmap.at( (first >> 2) & 0x3F );
|
||||
result[i + 1] = bmap.at(((first & 0x03) << 4) | ((second & 0xF0) >> 4));
|
||||
result[i + 2] = bmap.at(((second & 0x0F) << 2) | ((third & 0xC0) >> 6));
|
||||
result[i + 3] = bmap.at( (third & 0x3F) );
|
||||
result[j++] = emap.at( (first >> 2) & 0x3F );
|
||||
result[j++] = emap.at(((first & 0x03) << 4) | ((second & 0xF0) >> 4));
|
||||
result[j++] = emap.at(((second & 0x0F) << 2) | ((third & 0xC0) >> 6));
|
||||
result[j++] = emap.at( (third & 0x3F) );
|
||||
}
|
||||
|
||||
switch (len % 3) {
|
||||
case 2:
|
||||
{
|
||||
auto first = in[i];
|
||||
auto second = in[i+1];
|
||||
auto& first = in[i];
|
||||
auto& second = in[i+1];
|
||||
|
||||
result[i] = bmap.at( (first >> 2) & 0x3F );
|
||||
result[i + 1] = bmap.at(((first & 0x03) << 4) | ((second & 0xF0) >> 4));
|
||||
result[i + 2] = bmap.at( (second & 0x0F) << 2 );
|
||||
result[i + 3] = '=';
|
||||
result[j++] = emap.at( (first >> 2) & 0x3F );
|
||||
result[j++] = emap.at(((first & 0x03) << 4) | ((second & 0xF0) >> 4));
|
||||
result[j++] = emap.at( (second & 0x0F) << 2 );
|
||||
result[j++] = '=';
|
||||
break;
|
||||
}
|
||||
case 1:
|
||||
{
|
||||
auto& first = in[i];
|
||||
|
||||
result[i] = bmap.at((first >> 2) & 0x3F );
|
||||
result[i + 1] = bmap.at((first & 0x03) << 4 );
|
||||
result[i + 2] = '=';
|
||||
result[i + 3] = '=';
|
||||
result[j++] = emap.at((first >> 2) & 0x3F);
|
||||
result[j++] = emap.at((first & 0x03) << 4);
|
||||
result[j++] = '=';
|
||||
result[j++] = '=';
|
||||
break;
|
||||
}
|
||||
case 0:
|
||||
|
@ -135,7 +135,7 @@ std::string base64_decode(const char* in, size_t len)
|
|||
while (bytes_rem > 4)
|
||||
{
|
||||
// Error case in input
|
||||
if (dmap.at(*in) == -1) return;
|
||||
if (dmap.at(*in) == -1) return result;
|
||||
|
||||
auto first = dmap.at(in[0]);
|
||||
auto second = dmap.at(in[1]);
|
||||
|
|
10
include/jwt/detail/meta.hpp
Normal file
10
include/jwt/detail/meta.hpp
Normal file
|
@ -0,0 +1,10 @@
|
|||
#ifndef JWT_META_HPP
|
||||
#define JWT_META_HPP
|
||||
|
||||
namespace jwt {
|
||||
namespace detail {
|
||||
|
||||
}
|
||||
} // END namespace jwt
|
||||
|
||||
#endif
|
36
include/jwt/impl/jwt.ipp
Normal file
36
include/jwt/impl/jwt.ipp
Normal file
|
@ -0,0 +1,36 @@
|
|||
#ifndef JWT_IPP
|
||||
#define JWT_IPP
|
||||
|
||||
namespace jwt {
|
||||
|
||||
template <typename T>
|
||||
std::string to_json_str(const T& obj, bool pretty)
|
||||
{
|
||||
return pretty ? obj.create_json_obj().dump(2)
|
||||
: obj.create_json_obj().dump()
|
||||
;
|
||||
}
|
||||
|
||||
|
||||
template <typename T>
|
||||
std::ostream& write(std::ostream& os, const T& obj, bool pretty)
|
||||
{
|
||||
pretty ? (os << std::setw(2) << obj.create_json_obj())
|
||||
: (os << obj.create_json_obj())
|
||||
;
|
||||
|
||||
return os;
|
||||
}
|
||||
|
||||
|
||||
template <typename T>
|
||||
std::ostream& operator<< (std::ostream& os, const T& obj)
|
||||
{
|
||||
os << obj.create_json_obj();
|
||||
return os;
|
||||
}
|
||||
|
||||
} // END namespace jwt
|
||||
|
||||
|
||||
#endif
|
BIN
include/jwt/json/test_json
Executable file
BIN
include/jwt/json/test_json
Executable file
Binary file not shown.
21
include/jwt/json/test_json.cc
Normal file
21
include/jwt/json/test_json.cc
Normal file
|
@ -0,0 +1,21 @@
|
|||
#include <iostream>
|
||||
#include <string>
|
||||
#include "./json.hpp"
|
||||
|
||||
using json = nlohmann::json;
|
||||
|
||||
void basic_json_test()
|
||||
{
|
||||
json obj = json::object();
|
||||
obj["test"] = "value-test";
|
||||
obj["test-int"] = 42;
|
||||
|
||||
std::string jstr = obj.dump(0);
|
||||
std::cout << jstr << std::endl;
|
||||
}
|
||||
|
||||
int main() {
|
||||
basic_json_test();
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -1,8 +1,23 @@
|
|||
#ifndef JWT_HPP
|
||||
#define JWT_HPP
|
||||
|
||||
#include <cassert>
|
||||
#include <string>
|
||||
#include <ostream>
|
||||
|
||||
#include "jwt/base64.hpp"
|
||||
#include "jwt/string_view.hpp"
|
||||
#include "jwt/detail/meta.hpp"
|
||||
#include "jwt/json/json.hpp"
|
||||
|
||||
// For convenience
|
||||
using json_t = nlohmann::json;
|
||||
|
||||
namespace jwt {
|
||||
|
||||
/*!
|
||||
* JWT signing algorithm.
|
||||
*/
|
||||
enum class algorithm
|
||||
{
|
||||
NONE = 0,
|
||||
|
@ -19,6 +34,239 @@ enum class algorithm
|
|||
};
|
||||
|
||||
|
||||
/*!
|
||||
*/
|
||||
string_view alg_to_str(enum algorithm alg) noexcept
|
||||
{
|
||||
switch (alg) {
|
||||
case algorithm::HS256: return "HS256";
|
||||
case algorithm::HS384: return "HS384";
|
||||
case algorithm::HS512: return "HS512";
|
||||
case algorithm::RS256: return "RS256";
|
||||
case algorithm::RS384: return "RS384";
|
||||
case algorithm::RS512: return "RS512";
|
||||
case algorithm::ES256: return "ES256";
|
||||
case algorithm::ES384: return "ES384";
|
||||
case algorithm::ES512: return "ES512";
|
||||
case algorithm::TERM: return "TERM";
|
||||
case algorithm::NONE: return "NONE";
|
||||
default: assert (0 && "Unknown Algorithm");
|
||||
};
|
||||
|
||||
assert (0 && "Code not reached");
|
||||
}
|
||||
|
||||
|
||||
/*!
|
||||
*/
|
||||
enum class type
|
||||
{
|
||||
JWT = 0,
|
||||
};
|
||||
|
||||
|
||||
/*!
|
||||
*/
|
||||
string_view type_to_str(enum type typ)
|
||||
{
|
||||
switch (typ) {
|
||||
case type::JWT: return "JWT";
|
||||
default: assert (0 && "Unknown type");
|
||||
};
|
||||
|
||||
assert (0 && "Code not reached");
|
||||
}
|
||||
|
||||
|
||||
/*!
|
||||
* Registered claim names.
|
||||
*/
|
||||
enum class registered_claims
|
||||
{
|
||||
// Expiration Time claim
|
||||
expiration = 0,
|
||||
// Not Before Time claim
|
||||
not_before,
|
||||
// Issuer name claim
|
||||
issuer,
|
||||
// Audience claim
|
||||
audience,
|
||||
// Issued At Time claim
|
||||
issued_at,
|
||||
// Subject claim
|
||||
subject,
|
||||
// JWT ID claim
|
||||
jti,
|
||||
};
|
||||
|
||||
|
||||
/*!
|
||||
*/
|
||||
string_view reg_claims_to_str(enum registered_claims claim) noexcept
|
||||
{
|
||||
switch (claim) {
|
||||
case registered_claims::expiration: return "exp";
|
||||
case registered_claims::not_before: return "nbf";
|
||||
case registered_claims::issuer: return "iss";
|
||||
case registered_claims::audience: return "aud";
|
||||
case registered_claims::issued_at: return "iat";
|
||||
case registered_claims::subject: return "sub";
|
||||
case registered_claims::jti: return "jti";
|
||||
default: assert (0 && "Not a registered claim");
|
||||
};
|
||||
|
||||
assert (0 && "Code not reached");
|
||||
}
|
||||
|
||||
// Fwd declaration for friend functions to specify the
|
||||
// default arguments
|
||||
// See: https://stackoverflow.com/a/23336823/434233
|
||||
template <typename T>
|
||||
std::string to_json_str(const T& obj, bool pretty=false);
|
||||
|
||||
template <typename T>
|
||||
std::ostream& write(std::ostream& os, const T& obj, bool pretty=false);
|
||||
|
||||
/*!
|
||||
*/
|
||||
struct write_interface
|
||||
{
|
||||
/*!
|
||||
*/
|
||||
template <typename T>
|
||||
friend std::string to_json_str(const T& obj, bool pretty);
|
||||
|
||||
/*!
|
||||
*/
|
||||
template <typename T>
|
||||
friend std::ostream& write(
|
||||
std::ostream& os, const T& obj, bool pretty);
|
||||
|
||||
/*!
|
||||
*/
|
||||
template <typename T>
|
||||
friend std::ostream& operator<< (std::ostream& os, const T& obj);
|
||||
};
|
||||
|
||||
/*!
|
||||
*/
|
||||
template <typename Derived>
|
||||
struct base64_enc_dec
|
||||
{
|
||||
std::string base64_encode(bool with_pretty = false) const
|
||||
{
|
||||
std::string jstr = to_json_str(*static_cast<const Derived*>(this), with_pretty);
|
||||
return jwt::base64_encode(jstr.c_str(), jstr.length());
|
||||
}
|
||||
|
||||
static std::string base64_decode(const std::string& encoded_str)
|
||||
{
|
||||
return jwt::base64_decode(encoded_str.c_str(), encoded_str.length());
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
/*!
|
||||
* JWT Header.
|
||||
*/
|
||||
struct jwt_header: write_interface
|
||||
, base64_enc_dec<jwt_header>
|
||||
{
|
||||
public: // 'tors
|
||||
/*!
|
||||
*/
|
||||
jwt_header() = default;
|
||||
|
||||
/*!
|
||||
*/
|
||||
jwt_header(enum algorithm alg, enum type typ = type::JWT)
|
||||
: alg_(alg)
|
||||
, typ_(typ)
|
||||
{
|
||||
}
|
||||
|
||||
/// Default Copy and assignment
|
||||
jwt_header(const jwt_header&) = default;
|
||||
jwt_header& operator=(const jwt_header&) = default;
|
||||
|
||||
~jwt_header() = default;
|
||||
|
||||
public: // Exposed APIs
|
||||
/*!
|
||||
* NOTE: Any previously saved json dump or the encoding of the
|
||||
* header would not be valid after modifying the algorithm.
|
||||
*/
|
||||
void algo(enum algorithm alg) noexcept
|
||||
{
|
||||
alg_ = alg;
|
||||
}
|
||||
|
||||
/*!
|
||||
*/
|
||||
enum algorithm algo() const noexcept
|
||||
{
|
||||
return alg_;
|
||||
}
|
||||
|
||||
/*!
|
||||
* NOTE: Any previously saved json dump or the encoding of the
|
||||
* header would not be valid after modifying the type.
|
||||
*/
|
||||
void typ(enum type typ) noexcept
|
||||
{
|
||||
typ_ = typ;
|
||||
}
|
||||
|
||||
/*!
|
||||
*/
|
||||
enum type typ() const noexcept
|
||||
{
|
||||
return typ_;
|
||||
}
|
||||
|
||||
/*!
|
||||
*/
|
||||
json_t create_json_obj() const
|
||||
{
|
||||
json_t obj = json_t::object();
|
||||
obj["typ"] = type_to_str(typ_).to_string();
|
||||
obj["alg"] = alg_to_str(alg_).to_string();
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
private: // Data members
|
||||
/// The Algorithm to use for signature creation
|
||||
enum algorithm alg_ = algorithm::NONE;
|
||||
|
||||
/// The type of header
|
||||
enum type typ_ = type::JWT;
|
||||
};
|
||||
|
||||
/*!
|
||||
*/
|
||||
struct jwt_payload
|
||||
{
|
||||
};
|
||||
|
||||
/*!
|
||||
*/
|
||||
struct jwt_signature
|
||||
{
|
||||
};
|
||||
|
||||
|
||||
/*!
|
||||
*/
|
||||
class jwt_object
|
||||
{
|
||||
};
|
||||
|
||||
|
||||
} // END namespace jwt
|
||||
|
||||
|
||||
#include "jwt/impl/jwt.ipp"
|
||||
|
||||
#endif
|
||||
|
|
|
@ -342,6 +342,10 @@ private:
|
|||
};
|
||||
|
||||
|
||||
/// Helper typedef
|
||||
using string_view = basic_string_view<char>;
|
||||
|
||||
|
||||
} // END namespace jwt
|
||||
|
||||
#include "jwt/impl/string_view.ipp"
|
||||
|
|
BIN
include/jwt/test/test_jwt_header
Executable file
BIN
include/jwt/test/test_jwt_header
Executable file
Binary file not shown.
19
include/jwt/test/test_jwt_header.cc
Normal file
19
include/jwt/test/test_jwt_header.cc
Normal file
|
@ -0,0 +1,19 @@
|
|||
#include <iostream>
|
||||
#include "jwt/jwt.hpp"
|
||||
|
||||
void test_basic_header()
|
||||
{
|
||||
jwt::jwt_header hdr;
|
||||
hdr = jwt::jwt_header{jwt::algorithm::HS256};
|
||||
std::string jstr = to_json_str(hdr);
|
||||
std::cout << jstr << std::endl;
|
||||
|
||||
std::string enc_str = hdr.base64_encode();
|
||||
std::cout << "Base64: " << enc_str << std::endl;
|
||||
std::cout << "Decoded: " << jwt::jwt_header::base64_decode(enc_str) << std::endl;
|
||||
}
|
||||
|
||||
int main() {
|
||||
test_basic_header();
|
||||
return 0;
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue