added JWT library

This commit is contained in:
Günter Obiltschnig 2019-07-30 11:19:49 +02:00
parent d25b665194
commit 6c828018df
29 changed files with 2739 additions and 10 deletions

View File

@ -119,7 +119,7 @@ if(ENABLE_DATA_POSTGRESQL)
else()
find_package(PostgreSQL)
endif()
if(PostgreSQL_FOUND)
option(ENABLE_DATA "Enable SQL" ON)
option(ENABLE_DATA_POSTGRESQL "Enable SQL PosgreSQL" ON)
@ -154,6 +154,7 @@ option(ENABLE_PDF "Enable PDF" OFF)
option(ENABLE_UTIL "Enable Util" ON)
option(ENABLE_NET "Enable Net" ON)
option(ENABLE_NETSSL_WIN "Enable NetSSL Windows" OFF)
option(ENABLE_JWT "Enable JWT" OFF)
option(ENABLE_SEVENZIP "Enable SevenZip" OFF)
option(ENABLE_ZIP "Enable Zip" ON)
option(ENABLE_CPPPARSER "Enable C++ parser" OFF)
@ -227,7 +228,7 @@ endif()
if(ENABLE_PAGECOMPILER)
set(ENABLE_NET ON CACHE BOOL "Enable Net" FORCE)
set(ENABLE_UTIL ON CACHE BOOL "Enable Util" FORCE)
set(ENABLE_UTIL ON CACHE BOOL "Enable Util" FORCE)
endif()
if(ENABLE_MONGODB OR ENABLE_REDIS)
@ -269,6 +270,11 @@ if(ENABLE_NET AND ENABLE_TESTS)
set(ENABLE_UTIL ON CACHE BOOL "Enable Util" FORCE)
endif()
if(ENABLE_JWT)
set(ENABLE_CRYPTO ON CACHE BOOL "Enable Crypto" FORCE)
set(ENABLE_JSON ON CACHE BOOL "Enable JSON" FORCE)
endif()
if(ENABLE_PDF)
set(ENABLE_UTIL ON CACHE BOOL "Enable Util" FORCE)
set(ENABLE_XML ON CACHE BOOL "Enable XML" FORCE)
@ -282,7 +288,7 @@ endif()
if(ENABLE_SEVENZIP OR ENABLE_ZIP)
set(ENABLE_UTIL ON CACHE BOOL "Enable Util" FORCE)
set(ENABLE_XML ON CACHE BOOL "Enable XML" FORCE)
set(ENABLE_XML ON CACHE BOOL "Enable XML" FORCE)
endif()
if(ENABLE_UTIL AND ENABLE_TESTS)
@ -316,6 +322,11 @@ if(ENABLE_NET)
list(APPEND Poco_COMPONENTS "Net")
endif()
if(EXISTS ${PROJECT_SOURCE_DIR}/JWT AND ENABLE_JWT)
add_subdirectory(JWT)
list(APPEND Poco_COMPONENTS "JWT")
endif()
if(EXISTS ${PROJECT_SOURCE_DIR}/MongoDB AND ENABLE_MONGODB)
add_subdirectory(MongoDB)
list(APPEND Poco_COMPONENTS "MongoDB")
@ -366,7 +377,7 @@ if(EXISTS ${PROJECT_SOURCE_DIR}/Zip AND ENABLE_ZIP)
list(APPEND Poco_COMPONENTS "Zip")
endif()
if(APRUTIL_FOUND AND APACHE_FOUND AND
if(APRUTIL_FOUND AND APACHE_FOUND AND
EXISTS ${PROJECT_SOURCE_DIR}/ApacheConnector AND ENABLE_APACHECONNECTOR)
add_subdirectory(ApacheConnector)
list(APPEND Poco_COMPONENTS "ApacheConnector")
@ -447,7 +458,7 @@ if(POCO_UNBUNDLED)
DESTINATION "${PocoConfigPackageLocation}")
install(FILES cmake/V39/FindEXPAT.cmake
DESTINATION "${PocoConfigPackageLocation}/V39")
install(FILES cmake/V313/FindSQLite3.cmake
install(FILES cmake/V313/FindSQLite3.cmake
DESTINATION "${PocoConfigPackageLocation}/V313")
endif()

View File

@ -40,7 +40,7 @@ class Crypto_API ECDSADigestEngine: public Poco::DigestEngine
/// signed. Then, the hash value is encrypted, using
/// the ECDSA private key.
///
/// To verify a signature, pass it to the verify()
/// To verify a signature, pass it to the verify()
/// member function. It will decrypt the signature
/// using the ECDSA public key and compare the resulting
/// hash with the actual hash of the data.
@ -64,11 +64,11 @@ public:
void reset();
/// Resets the engine so that a new
/// digest can be computed.
const DigestEngine::Digest& digest();
/// Finishes the computation of the digest
/// Finishes the computation of the digest
/// (the first time it's called) and
/// returns the message digest.
/// returns the message digest.
///
/// Can be called multiple times.
@ -95,6 +95,35 @@ private:
};
class Crypto_API ECDSASignature
/// A helper class for dealing with ECDSA signatures.
{
public:
typedef std::vector<unsigned char> ByteVec;
explicit ECDSASignature(const ByteVec& derSignature);
/// Creates the ECDSASignature from a DER-encoded signature.
ECDSASignature(const ByteVec& rawR, const ByteVec& rawS);
/// Creates the ECDSASignature from raw r and s values.
~ECDSASignature();
/// Destroys the ECDSASignature.
ByteVec toDER() const;
/// Returns a buffer containing the DER-encoded signature.
ByteVec rawR() const;
/// Returns a raw P value.
ByteVec rawS() const;
/// Returns a raw Q value.
private:
ECDSA_SIG* _pSig;
};
} } // namespace Poco::Crypto

View File

@ -14,6 +14,7 @@
#include "Poco/Crypto/ECDSADigestEngine.h"
#include "Poco/Crypto/CryptoException.h"
#include <openssl/ecdsa.h>
@ -21,6 +22,11 @@ namespace Poco {
namespace Crypto {
//
// ECDSADigestEngine
//
ECDSADigestEngine::ECDSADigestEngine(const ECKey& key, const std::string &name):
_key(key),
_engine(name)
@ -46,7 +52,7 @@ void ECDSADigestEngine::reset()
_signature.clear();
}
const DigestEngine::Digest& ECDSADigestEngine::digest()
{
if (_digest.empty())
@ -97,4 +103,104 @@ void ECDSADigestEngine::updateImpl(const void* data, std::size_t length)
}
//
// ECDSASignature
//
ECDSASignature::ECDSASignature(const ByteVec& derSignature)
{
poco_assert (!derSignature.empty());
const unsigned char* p = &derSignature[0];
_pSig = d2i_ECDSA_SIG(0, &p, derSignature.size());
if (!_pSig)
throw OpenSSLException();
}
ECDSASignature::ECDSASignature(const ByteVec& rawR, const ByteVec& rawS):
_pSig(ECDSA_SIG_new())
{
poco_assert (!rawR.empty() && !rawS.empty());
if (!_pSig) throw CryptoException("cannot allocate ECDSA signature");
try
{
#if OPENSSL_VERSION_NUMBER >= 0x10100000L
ECDSA_SIG_set0(_pSig,
BN_bin2bn(&rawR[0], rawR.size(), 0),
BN_bin2bn(&rawS[0], rawS.size(), 0));
if (ECDSA_SIG_get0_r(_pSig) == 0 || ECDSA_SIG_get0_s(_pSig) == 0)
throw CryptoException("failed to decode R and S values");
#else
if (!BN_bin2bn(&rawR[0], rawR.size(), _pSig->r))
throw OpenSSLException();
if (!BN_bin2bn(&rawS[0], rawS.size(), _pSig->s))
throw OpenSSLException();
#endif
}
catch (...)
{
ECDSA_SIG_free(_pSig);
throw;
}
}
ECDSASignature::~ECDSASignature()
{
ECDSA_SIG_free(_pSig);
}
ECDSASignature::ByteVec ECDSASignature::toDER() const
{
int size = i2d_ECDSA_SIG(_pSig, 0);
if (size > 0)
{
ByteVec buffer(size);
unsigned char* p = &buffer[0];
i2d_ECDSA_SIG(_pSig, &p);
return buffer;
}
else throw OpenSSLException();
}
ECDSASignature::ByteVec ECDSASignature::rawR() const
{
ByteVec buffer;
#if OPENSSL_VERSION_NUMBER >= 0x10100000L
const BIGNUM* pR = ECDSA_SIG_get0_r(_pSig);
#else
const BIGNUM* pR = _pSig->r;
#endif
if (pR)
{
buffer.resize(BN_num_bytes(pR));
BN_bn2bin(pR, &buffer[0]);
}
return buffer;
}
ECDSASignature::ByteVec ECDSASignature::rawS() const
{
ByteVec buffer;
#if OPENSSL_VERSION_NUMBER >= 0x10100000L
const BIGNUM* pS = ECDSA_SIG_get0_s(_pSig);
#else
const BIGNUM* pS = _pSig->s;
#endif
if (pS)
{
buffer.resize(BN_num_bytes(pS));
BN_bn2bin(pS, &buffer[0]);
}
return buffer;
}
} } // namespace Poco::Crypto

37
JWT/CMakeLists.txt Normal file
View File

@ -0,0 +1,37 @@
# Sources
file(GLOB SRCS_G "src/*.cpp")
POCO_SOURCES_AUTO( SRCS ${SRCS_G})
# Headers
file(GLOB_RECURSE HDRS_G "include/*.h" )
POCO_HEADERS_AUTO( SRCS ${HDRS_G})
# Version Resource
if(MSVC AND NOT POCO_STATIC)
source_group("Resources" FILES ${CMAKE_SOURCE_DIR}/DLLVersion.rc)
list(APPEND SRCS ${CMAKE_SOURCE_DIR}/DLLVersion.rc)
endif()
add_library(JWT ${SRCS} )
add_library(Poco::JWT ALIAS JWT)
set_target_properties( JWT
PROPERTIES
VERSION ${SHARED_LIBRARY_VERSION} SOVERSION ${SHARED_LIBRARY_VERSION}
OUTPUT_NAME PocoJWT
DEFINE_SYMBOL JWT_EXPORTS
)
target_link_libraries(JWT PUBLIC Poco::JSON Poco::Crypto)
target_include_directories(JWT
PUBLIC
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
$<INSTALL_INTERFACE:include>
PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/src
)
POCO_INSTALL(JWT)
POCO_GENERATE_PACKAGE(JWT)
if (ENABLE_TESTS)
add_subdirectory(testsuite)
endif ()

15
JWT/Makefile Normal file
View File

@ -0,0 +1,15 @@
#
# Makefile
#
# Makefile for Poco JWT
#
include $(POCO_BASE)/build/rules/global
objects = Token Signer Serializer JWTException
target = PocoJWT
target_version = $(LIBVERSION)
target_libs = PocoCrypto PocoJSON PocoFoundation
include $(POCO_BASE)/build/rules/lib

View File

@ -0,0 +1,5 @@
include(CMakeFindDependencyMacro)
find_dependency(PocoFoundation)
find_dependency(PocoJSON)
find_dependency(PocoCrypto)
include("${CMAKE_CURRENT_LIST_DIR}/PocoJWTTargets.cmake")

View File

@ -0,0 +1,62 @@
//
// JWT.h
//
// Library: JWT
// Package: JWT
// Module: JWT
//
// Basic definitions for the Poco JWT library.
// This file must be the first file included by every other JWT
// header file.
//
// Copyright (c) 2019, Applied Informatics Software Engineering GmbH.
// and Contributors.
//
// SPDX-License-Identifier: BSL-1.0
//
#ifndef JWT_JWT_INCLUDED
#define JWT_JWT_INCLUDED
#include "Poco/Foundation.h"
//
// The following block is the standard way of creating macros which make exporting
// from a DLL simpler. All files within this DLL are compiled with the JWT_EXPORTS
// symbol defined on the command line. this symbol should not be defined on any project
// that uses this DLL. This way any other project whose source files include this file see
// JWT_API functions as being imported from a DLL, whereas this DLL sees symbols
// defined with this macro as being exported.
//
#if defined(_WIN32) && defined(POCO_DLL)
#if defined(JWT_EXPORTS)
#define JWT_API __declspec(dllexport)
#else
#define JWT_API __declspec(dllimport)
#endif
#endif
#if !defined(JWT_API)
#if !defined(POCO_NO_GCC_API_ATTRIBUTE) && defined (__GNUC__) && (__GNUC__ >= 4)
#define JWT_API __attribute__ ((visibility ("default")))
#else
#define JWT_API
#endif
#endif
//
// Automatically link JWT library.
//
#if defined(_MSC_VER)
#if !defined(POCO_NO_AUTOMATIC_LIBS) && !defined(JWT_EXPORTS)
#pragma comment(lib, "PocoJWT" POCO_LIB_SUFFIX)
#endif
#endif
#endif // JWT_JWT_INCLUDED

View File

@ -0,0 +1,41 @@
//
// JWTException.h
//
// Library: JWT
// Package: JWT
// Module: JWTException
//
// Definition of the JWTException class.
//
// Copyright (c) 2019, Applied Informatics Software Engineering GmbH.
// and Contributors.
//
// SPDX-License-Identifier: BSL-1.0
//
#ifndef JWT_JWTException_INCLUDED
#define JWT_JWTException_INCLUDED
#include "Poco/JWT/JWT.h"
#include "Poco/Exception.h"
namespace Poco {
namespace JWT {
POCO_DECLARE_EXCEPTION(JWT_API, JWTException, Poco::Exception)
POCO_DECLARE_EXCEPTION(JWT_API, ParseException, JWTException)
POCO_DECLARE_EXCEPTION(JWT_API, UnsupportedAlgorithmException, JWTException)
POCO_DECLARE_EXCEPTION(JWT_API, UnallowedAlgorithmException, JWTException)
POCO_DECLARE_EXCEPTION(JWT_API, SignatureException, JWTException)
POCO_DECLARE_EXCEPTION(JWT_API, SignatureVerificationException, SignatureException)
POCO_DECLARE_EXCEPTION(JWT_API, SignatureGenerationException, SignatureException)
} } // namespace Poco::JWT
#endif // JWT_JWTException_INCLUDED

View File

@ -0,0 +1,53 @@
//
// Serializer.h
//
// Library: JWT
// Package: JWT
// Module: Serializer
//
// Definition of the Serializer class.
//
// Copyright (c) 2019, Applied Informatics Software Engineering GmbH.
// and Contributors.
//
// SPDX-License-Identifier: BSL-1.0
//
#ifndef JWT_Serializer_INCLUDED
#define JWT_Serializer_INCLUDED
#include "Poco/JWT/JWT.h"
#include "Poco/JSON/Object.h"
namespace Poco {
namespace JWT {
class JWT_API Serializer
/// A helper class for serializing and deserializing JWTs.
{
public:
static std::string serialize(const Poco::JSON::Object& object);
/// Serializes and base64-encodes a JSON object.
static void serialize(const Poco::JSON::Object& object, std::ostream& stream);
/// Serializes and base64-encodes a JSON object.
static Poco::JSON::Object::Ptr deserialize(const std::string& serialized);
/// Attempts to deserialize a base64-encoded serialized JSON object.
static Poco::JSON::Object::Ptr deserialize(std::istream& stream);
/// Attempts to deserialize a base64-encoded serialized JSON object.
static std::vector<std::string> split(const std::string& token);
/// Splits a serialized JWT into its components.
};
} } // namespace Poco::JWT
#endif // JWT_Serializer_INCLUDED

View File

@ -0,0 +1,196 @@
//
// Signer.h
//
// Library: JWT
// Package: JWT
// Module: Signer
//
// Definition of the Signer class.
//
// Copyright (c) 2019, Applied Informatics Software Engineering GmbH.
// and Contributors.
//
// SPDX-License-Identifier: BSL-1.0
//
#ifndef JWT_Signer_INCLUDED
#define JWT_Signer_INCLUDED
#include "Poco/JWT/JWT.h"
#include "Poco/JWT/Token.h"
#include "Poco/Crypto/RSAKey.h"
#include "Poco/Crypto/ECKey.h"
#include "Poco/DigestEngine.h"
#include <set>
namespace Poco {
namespace JWT {
class JWT_API Signer
/// This class signs and verifies the signature of JSON Web Tokens.
///
/// The following signing algorithms are supported:
/// - HS256 (HMAC using SHA256)
/// - HS384 (HMAC using SHA384)
/// - HS512 (HMAC using SHA512)
/// - RS256 (RSA SSA PKCS1 v1.5 using SHA256)
/// - RS384 (RSA SSA PKCS1 v1.5 using SHA384)
/// - RS512 (RSA SSA PKCS1 v1.5 using SHA512)
/// - ES256 (ECDSA using P-256 and SHA-256)
/// - ES384 (ECDSA using P-256 and SHA-384)
/// - ES512 (ECDSA using P-256 and SHA-512)
{
public:
Signer();
/// Creates a Signer.
///
/// For signing and verification, a key must be set using the
/// setHMACKey(), setRSAKey() or setECKey() methods.
///
/// Sets HS256 as the only allowed algorithm.
/// Call setAlgorithms() or addAlgorithm() to allow additional
/// algorithms for verification.
explicit Signer(const std::string& hmacKey);
/// Creates the Signer using the given secret/key for HMAC-based signing and verification.
///
/// Sets HS256 as the only allowed algorithm.
/// Call setAlgorithms() or addAlgorithm() to allow additional
/// algorithms for verification.
explicit Signer(const Poco::SharedPtr<Poco::Crypto::RSAKey>& pRSAKey);
/// Creates the Signer using the given secret/key for RSA-based signing and verification.
///
/// Sets HS256 as the only allowed algorithm.
/// Call setAlgorithms() or addAlgorithm() to allow additional
/// algorithms for verification.
explicit Signer(const Poco::SharedPtr<Poco::Crypto::ECKey>& pECKey);
/// Creates the Signer using the given secret/key for EC-based signing and verification.
///
/// Sets HS256 as the only allowed algorithm.
/// Call setAlgorithms() or addAlgorithm() to allow additional
/// algorithms for verification.
~Signer();
/// Destroys the Signer.
Signer& setAlgorithms(const std::set<std::string>& algorithms);
/// Sets the allowed algorithms for signing.
///
/// When verifying JWTs, the algorithm used for signing
/// must be one of the allowed algorithms.
const std::set<std::string>& getAlgorithms() const;
/// Returns the allowed algorithms for signing.
Signer& addAlgorithm(const std::string& algorithm);
/// Adds an algorithm to the set of allowed algorithms.
Signer& addAllAlgorithms();
/// Adds all supported algorithm to the set of allowed algorithms.
Signer& setHMACKey(const std::string& key);
/// Sets the key used for HMAC-based signing and verification.
const std::string getHMACKey() const;
/// Returns the key used for HMAC-based signing and verification.
Signer& setRSAKey(const Poco::SharedPtr<Poco::Crypto::RSAKey>& pKey);
/// Sets the key used for RSA-based signing and verification.
Poco::SharedPtr<Poco::Crypto::RSAKey> getRSAKey() const;
/// Returns the key used for RSA-based signing and verification.
Signer& setECKey(const Poco::SharedPtr<Poco::Crypto::ECKey>& pKey);
/// Sets the key used for EC-based signing and verification.
Poco::SharedPtr<Poco::Crypto::ECKey> getECKey() const;
/// Returns the key used for EC-based signing and verification.
std::string sign(Token& token, const std::string& algorithm) const;
/// Signs the given token using the given algorithm.
///
/// An appropriate key must have been provided prior to calling sign().
///
/// Returns the serialized JWT including the signature.
Token verify(const std::string& jwt) const;
/// Verifies the given serialized JSON Web Token.
///
/// An appropriate key must have been provided prior to calling verify().
///
/// If successful, returns a Token object.
/// If not successful, throws a SignatureVerificationException.
bool tryVerify(const std::string& jwt, Token& token) const;
/// Verifies the given serialized JSON Web Token and stores
/// it in the given Token object.
///
/// An appropriate key must have been provided prior to calling verify().
///
/// If successful, returns true, otherwise false.
static const std::string ALGO_NONE;
static const std::string ALGO_HS256;
static const std::string ALGO_HS384;
static const std::string ALGO_HS512;
static const std::string ALGO_RS256;
static const std::string ALGO_RS384;
static const std::string ALGO_RS512;
static const std::string ALGO_ES256;
static const std::string ALGO_ES384;
static const std::string ALGO_ES512;
protected:
static std::string encode(const Poco::DigestEngine::Digest& digest);
static Poco::DigestEngine::Digest decode(const std::string& signature);
private:
Signer(const Signer&);
Signer& operator = (const Signer&);
std::set<std::string> _algorithms;
std::string _hmacKey;
Poco::SharedPtr<Poco::Crypto::RSAKey> _pRSAKey;
Poco::SharedPtr<Poco::Crypto::ECKey> _pECKey;
};
//
// inlines
//
inline const std::set<std::string>& Signer::getAlgorithms() const
{
return _algorithms;
}
inline const std::string Signer::getHMACKey() const
{
return _hmacKey;
}
inline Poco::SharedPtr<Poco::Crypto::RSAKey> Signer::getRSAKey() const
{
return _pRSAKey;
}
inline Poco::SharedPtr<Poco::Crypto::ECKey> Signer::getECKey() const
{
return _pECKey;
}
} } // namespace Poco::JWT
#endif // JWT_Signer_INCLUDED

View File

@ -0,0 +1,336 @@
//
// Token.h
//
// Library: JWT
// Package: JWT
// Module: Token
//
// Definition of the Token class.
//
// Copyright (c) 2019, Applied Informatics Software Engineering GmbH.
// and Contributors.
//
// SPDX-License-Identifier: BSL-1.0
//
#ifndef JWT_Token_INCLUDED
#define JWT_Token_INCLUDED
#include "Poco/JWT/JWT.h"
#include "Poco/JSON/Object.h"
#include "Poco/Timestamp.h"
namespace Poco {
namespace JWT {
class JWT_API Token
/// This class represents a JSON Web Token (JWT) according to RFC 7519.
///
/// To create and sign a JWT (using the Signer class):
///
/// Token token;
/// token.setType("JWT");
/// token.setSubject("1234567890");
/// token.payload().set("name", std::string("John Doe"));
/// token.setIssuedAt(Poco::Timestamp()));
///
/// Signer signer("0123456789ABCDEF0123456789ABCDEF");
/// std::string jwt = signer.sign(token, Signer::ALGO_HS256);
///
/// To verify a signed token:
///
/// std::string jwt(
/// "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9."
/// "eyJpYXQiOjE1MTYyMzkwMjIsIm5hbWUiOiJKb2huIERvZSIsInN1YiI6IjEyMzQ1Njc4OTAifQ."
/// "qn9G7NwFEOjIh-7hfCUDZA1aJeQmf7I7YvzCBcdenGw");
///
/// Signer signer("0123456789ABCDEF0123456789ABCDEF");
/// Token token = signer.verify(jwt);
{
public:
Token();
/// Creates an empty JSON Web Token.
explicit Token(const std::string& token);
/// Creates a JSON Web Token from its serialized string representation.
Token(const Token& token);
/// Creates a JSON Web Token by copying another one.
~Token();
/// Destroys the Token.
Token& operator = (const Token& token);
/// Assignment operator.
Token& operator = (const std::string& token);
/// Parses and assigns serialized JWT.
std::string toString() const;
/// Returns the serialized string representation of the JSON Web Token.
const Poco::JSON::Object& header() const;
/// Returns the header JSON object.
Poco::JSON::Object& header();
/// Returns the header JSON object.
const Poco::JSON::Object& payload() const;
/// Returns the payload JSON object.
Poco::JSON::Object& payload();
/// Returns the payload JSON object.
const std::string& signature() const;
/// Returns the signature string.
void setIssuer(const std::string& issuer);
/// Sets the issuer ("iss" claim in payload).
std::string getIssuer() const;
/// Returns the issuer, or an empty string if no issuer has been specified.
void setSubject(const std::string& subject);
/// Sets the subject ("sub" claim in paylod).
std::string getSubject() const;
/// Returns the subject, or an empty string if no issuer has been specified.
void setAudience(const std::string& audience);
/// Sets the audience ("aud" claim in payload) to a single value.
void setAudience(const std::vector<std::string>& audience);
/// Sets the audience ("aud" claim in payload).
std::vector<std::string> getAudience() const;
/// Returns the audience.
void setExpiration(const Poco::Timestamp& expiration);
/// Sets the expiration ("exp" claim in payload).
Poco::Timestamp getExpiration() const;
/// Returns the expiration, or a zero Poco::Timestamp if no expiration has been specified.
void setNotBefore(const Poco::Timestamp& notBefore);
/// Sets the not-before time ("nbf" claim in payload).
Poco::Timestamp getNotBefore() const;
/// Returns the not-before time, or a zero Poco::Timestamp if no not-before time has been specified.
void setIssuedAt(const Poco::Timestamp& issuedAt);
/// Sets the issued-at time ("iat" claim in payload).
Poco::Timestamp getIssuedAt() const;
/// Returns the issued-at time, or a zero Poco::Timestamp if no issued-at time has been specified.
void setId(const std::string& id);
/// Sets the JWT ID ("jti" claim in payload).
std::string getId() const;
/// Returns the JWT ID, or an empty string if no JWT ID has been specified.
void setType(const std::string& type);
/// Sets the JWT type ("typ" claim in payload).
std::string getType() const;
/// Returns the JWT type or an empty string if no type has been specified.
void setAlgorithm(const std::string& algorithm);
/// Sets the JWT signature algorithm ("alg" claim in header).
std::string getAlgorithm() const;
/// Returns the JWT signature algorithm, or an empty string if no algorithm has been specified.
void setContentType(const std::string& contentType);
/// Sets the JWT content type ("cty" claim in header").
std::string getContentType() const;
/// Returns the JWT content type, or an empty string if no content type has been specified.
static const std::string CLAIM_ISSUER;
static const std::string CLAIM_SUBJECT;
static const std::string CLAIM_AUDIENCE;
static const std::string CLAIM_EXPIRATION;
static const std::string CLAIM_NOT_BEFORE;
static const std::string CLAIM_ISSUED_AT;
static const std::string CLAIM_JWT_ID;
static const std::string CLAIM_TYPE;
static const std::string CLAIM_ALGORITHM;
static const std::string CLAIM_CONTENT_TYPE;
protected:
Token(const std::string& header, const std::string& payload, const std::string& signature);
void sign(const std::string& signature);
void setTimestamp(const std::string& claim, const Poco::Timestamp& ts);
Poco::Timestamp getTimestamp(const std::string& claim) const;
void assign(const std::string& header, const std::string& payload, const std::string& signature);
private:
Poco::JSON::Object::Ptr _pHeader;
Poco::JSON::Object::Ptr _pPayload;
std::string _signature;
static const std::string EMPTY;
friend class Signer;
};
//
// inlines
//
inline const Poco::JSON::Object& Token::header() const
{
return *_pHeader;
}
inline Poco::JSON::Object& Token::header()
{
return *_pHeader;
}
inline const Poco::JSON::Object& Token::payload() const
{
return *_pPayload;
}
inline Poco::JSON::Object& Token::payload()
{
return *_pPayload;
}
inline const std::string& Token::signature() const
{
return _signature;
}
inline void Token::setIssuer(const std::string& issuer)
{
_pPayload->set(CLAIM_ISSUER, issuer);
}
inline std::string Token::getIssuer() const
{
return _pPayload->optValue(CLAIM_ISSUER, EMPTY);
}
inline void Token::setSubject(const std::string& subject)
{
_pPayload->set(CLAIM_SUBJECT, subject);
}
inline std::string Token::getSubject() const
{
return _pPayload->optValue(CLAIM_SUBJECT, EMPTY);
}
inline void Token::setAudience(const std::string& audience)
{
_pPayload->set(CLAIM_AUDIENCE, audience);
}
inline void Token::setExpiration(const Poco::Timestamp& expiration)
{
setTimestamp(CLAIM_EXPIRATION, expiration);
}
inline Poco::Timestamp Token::getExpiration() const
{
return getTimestamp(CLAIM_EXPIRATION);
}
inline void Token::setNotBefore(const Poco::Timestamp& notBefore)
{
setTimestamp(CLAIM_NOT_BEFORE, notBefore);
}
inline Poco::Timestamp Token::getNotBefore() const
{
return getTimestamp(CLAIM_NOT_BEFORE);
}
inline void Token::setIssuedAt(const Poco::Timestamp& issuedAt)
{
setTimestamp(CLAIM_ISSUED_AT, issuedAt);
}
inline Poco::Timestamp Token::getIssuedAt() const
{
return getTimestamp(CLAIM_ISSUED_AT);
}
inline void Token::setId(const std::string& id)
{
_pPayload->set(CLAIM_JWT_ID, id);
}
inline std::string Token::getId() const
{
return _pPayload->optValue(CLAIM_JWT_ID, EMPTY);
}
inline void Token::setType(const std::string& type)
{
_pHeader->set(CLAIM_TYPE, type);
}
inline std::string Token::getType() const
{
return _pHeader->optValue(CLAIM_TYPE, EMPTY);
}
inline void Token::setAlgorithm(const std::string& algorithm)
{
_pHeader->set(CLAIM_ALGORITHM, algorithm);
}
inline std::string Token::getAlgorithm() const
{
return _pHeader->optValue(CLAIM_ALGORITHM, EMPTY);
}
inline void Token::setContentType(const std::string& contentType)
{
_pHeader->set(CLAIM_CONTENT_TYPE, contentType);
}
inline std::string Token::getContentType() const
{
return _pHeader->optValue(CLAIM_CONTENT_TYPE, EMPTY);
}
} } // namespace Poco::JWT
#endif // JWT_Token_INCLUDED

35
JWT/src/JWTException.cpp Normal file
View File

@ -0,0 +1,35 @@
//
// JWTException.cpp
//
// Library: JWT
// Package: JWT
// Module: JWTException
//
// Copyright (c) 2019, Applied Informatics Software Engineering GmbH.
// and Contributors.
//
// SPDX-License-Identifier: BSL-1.0
//
#include "Poco/JWT/JWTException.h"
#include <typeinfo>
using Poco::Exception;
namespace Poco {
namespace JWT {
POCO_IMPLEMENT_EXCEPTION(JWTException, Exception, "JWT Exception")
POCO_IMPLEMENT_EXCEPTION(ParseException, JWTException, "JWT parsing failed")
POCO_IMPLEMENT_EXCEPTION(UnsupportedAlgorithmException, JWTException, "Unsupported signing algorithm")
POCO_IMPLEMENT_EXCEPTION(UnallowedAlgorithmException, JWTException, "Unallowed signing algorithm")
POCO_IMPLEMENT_EXCEPTION(SignatureException, JWTException, "JWT Signature Exception")
POCO_IMPLEMENT_EXCEPTION(SignatureVerificationException, SignatureException, "JWT signature verification failed")
POCO_IMPLEMENT_EXCEPTION(SignatureGenerationException, SignatureException, "JWT signature generation failed")
} } // namespace Poco::JWT

81
JWT/src/Serializer.cpp Normal file
View File

@ -0,0 +1,81 @@
//
// Serializer.cpp
//
// Library: JWT
// Package: JWT
// Module: Serializer
//
// Copyright (c) 2019, Applied Informatics Software Engineering GmbH.
// and Contributors.
//
// SPDX-License-Identifier: BSL-1.0
//
#include "Poco/JWT/Serializer.h"
#include "Poco/JWT/JWTException.h"
#include "Poco/JSON/Parser.h"
#include "Poco/Base64Encoder.h"
#include "Poco/Base64Decoder.h"
#include "Poco/MemoryStream.h"
#include "Poco/StringTokenizer.h"
#include <sstream>
namespace Poco {
namespace JWT {
std::string Serializer::serialize(const Poco::JSON::Object& object)
{
std::ostringstream stream;
serialize(object, stream);
return stream.str();
}
void Serializer::serialize(const Poco::JSON::Object& object, std::ostream& stream)
{
Poco::Base64Encoder encoder(stream, Poco::BASE64_URL_ENCODING | Poco::BASE64_NO_PADDING);
object.stringify(encoder);
encoder.close();
}
Poco::JSON::Object::Ptr Serializer::deserialize(const std::string& serialized)
{
Poco::MemoryInputStream stream(serialized.data(), serialized.size());
return deserialize(stream);
}
Poco::JSON::Object::Ptr Serializer::deserialize(std::istream& stream)
{
Poco::Base64Decoder decoder(stream, Poco::BASE64_URL_ENCODING | Poco::BASE64_NO_PADDING);
Poco::JSON::Parser parser;
try
{
Poco::Dynamic::Var json = parser.parse(decoder);
Poco::JSON::Object::Ptr pObject = json.extract<Poco::JSON::Object::Ptr>();
return pObject;
}
catch (Poco::BadCastException&)
{
throw ParseException("String does not deserialize to a JSON object");
}
catch (Poco::Exception& exc)
{
throw ParseException("Failed to deserialize JWT component", exc.displayText());
}
}
std::vector<std::string> Serializer::split(const std::string& token)
{
Poco::StringTokenizer tokenizer(token, ".");
std::vector<std::string> result(tokenizer.begin(), tokenizer.end());
return result;
}
} } // namespace Poco::JWT

503
JWT/src/Signer.cpp Normal file
View File

@ -0,0 +1,503 @@
//
// Signer.cpp
//
// Library: JWT
// Package: JWT
// Module: Signer
//
// Copyright (c) 2019, Applied Informatics Software Engineering GmbH.
// and Contributors.
//
// SPDX-License-Identifier: BSL-1.0
//
#include "Poco/JWT/Signer.h"
#include "Poco/JWT/Serializer.h"
#include "Poco/JWT/JWTException.h"
#include "Poco/HMACEngine.h"
#include "Poco/RefCountedObject.h"
#include "Poco/AutoPtr.h"
#include "Poco/DynamicFactory.h"
#include "Poco/MemoryStream.h"
#include "Poco/Base64Encoder.h"
#include "Poco/Base64Decoder.h"
#include "Poco/Crypto/DigestEngine.h"
#include "Poco/Crypto/RSADigestEngine.h"
#include "Poco/Crypto/ECDSADigestEngine.h"
#include <sstream>
namespace Poco {
namespace JWT {
//
// Algorithm
//
class Algorithm: public Poco::RefCountedObject
/// Abstraction of an algorithm for signing JWTs.
{
public:
typedef Poco::AutoPtr<Algorithm> Ptr;
Algorithm();
/// Creates the Algorithm.
virtual ~Algorithm();
/// Destroys the Algorithm.
virtual Poco::DigestEngine::Digest sign(const Signer& signer, const std::string& header, const std::string& payload) = 0;
/// Signs the header and payload and returns the signature.
virtual bool verify(const Signer& signer, const std::string& header, const std::string& payload, const Poco::DigestEngine::Digest& signature) = 0;
/// Verifies the header and payload against the signature.
///
/// Returns true if the signature is correct, otherwise false.
static const std::string SHA256;
static const std::string SHA384;
static const std::string SHA512;
};
Algorithm::Algorithm()
{
}
Algorithm::~Algorithm()
{
}
const std::string Algorithm::SHA256("SHA256");
const std::string Algorithm::SHA384("SHA384");
const std::string Algorithm::SHA512("SHA512");
class SHA256Engine: public Poco::Crypto::DigestEngine
{
public:
enum
{
BLOCK_SIZE = 64,
DIGEST_SIZE = 32
};
SHA256Engine():
Poco::Crypto::DigestEngine(Algorithm::SHA256)
{
}
};
class SHA384Engine: public Poco::Crypto::DigestEngine
{
public:
enum
{
BLOCK_SIZE = 128,
DIGEST_SIZE = 48
};
SHA384Engine():
Poco::Crypto::DigestEngine(Algorithm::SHA384)
{
}
};
class SHA512Engine: public Poco::Crypto::DigestEngine
{
public:
enum
{
BLOCK_SIZE = 128,
DIGEST_SIZE = 64
};
SHA512Engine():
Poco::Crypto::DigestEngine(Algorithm::SHA512)
{
}
};
template <typename Engine>
class HMACAlgorithm: public Algorithm
{
public:
Poco::DigestEngine::Digest sign(const Signer& signer, const std::string& header, const std::string& payload)
{
Poco::HMACEngine<Engine> hmac(signer.getHMACKey());
hmac.update(header);
hmac.update('.');
hmac.update(payload);
return hmac.digest();
}
bool verify(const Signer& signer, const std::string& header, const std::string& payload, const Poco::DigestEngine::Digest& signature)
{
return sign(signer, header, payload) == signature;
}
};
typedef HMACAlgorithm<SHA256Engine> HS256;
typedef HMACAlgorithm<SHA384Engine> HS384;
typedef HMACAlgorithm<SHA512Engine> HS512;
class RSAAlgorithm: public Algorithm
{
public:
RSAAlgorithm(const std::string& digestType):
_digestType(digestType)
{
}
Poco::DigestEngine::Digest sign(const Signer& signer, const std::string& header, const std::string& payload)
{
if (!signer.getRSAKey()) throw SignatureGenerationException("No RSA key available");
Poco::Crypto::RSADigestEngine rsa(*signer.getRSAKey(), _digestType);
rsa.update(header);
rsa.update('.');
rsa.update(payload);
return rsa.signature();
}
bool verify(const Signer& signer, const std::string& header, const std::string& payload, const Poco::DigestEngine::Digest& signature)
{
if (!signer.getRSAKey()) throw SignatureVerificationException("No RSA key available");
Poco::Crypto::RSADigestEngine rsa(*signer.getRSAKey(), _digestType);
rsa.update(header);
rsa.update('.');
rsa.update(payload);
return rsa.verify(signature);
}
private:
std::string _digestType;
};
class RS256: public RSAAlgorithm
{
public:
RS256():
RSAAlgorithm(Algorithm::SHA256)
{
}
};
class RS384: public RSAAlgorithm
{
public:
RS384():
RSAAlgorithm(Algorithm::SHA384)
{
}
};
class RS512: public RSAAlgorithm
{
public:
RS512():
RSAAlgorithm(Algorithm::SHA512)
{
}
};
class ECDSAAlgorithm: public Algorithm
{
public:
ECDSAAlgorithm(const std::string& digestType):
_digestType(digestType)
{
}
Poco::DigestEngine::Digest sign(const Signer& signer, const std::string& header, const std::string& payload)
{
if (!signer.getECKey()) throw SignatureGenerationException("No EC key available");
Poco::Crypto::ECDSADigestEngine ecdsa(*signer.getECKey(), _digestType);
ecdsa.update(header);
ecdsa.update('.');
ecdsa.update(payload);
Poco::Crypto::ECDSASignature ecdsaSig(ecdsa.signature());
Poco::DigestEngine::Digest jwtSig(ecdsaSig.rawR());
Poco::DigestEngine::Digest rawS(ecdsaSig.rawS());
jwtSig.insert(jwtSig.end(), rawS.begin(), rawS.end());
return jwtSig;
}
bool verify(const Signer& signer, const std::string& header, const std::string& payload, const Poco::DigestEngine::Digest& signature)
{
if (!signer.getECKey()) throw SignatureVerificationException("No EC key available");
Poco::DigestEngine::Digest rawR(signature.begin(), signature.begin() + signature.size() / 2);
Poco::DigestEngine::Digest rawS(signature.begin() + signature.size() / 2, signature.end());
Poco::Crypto::ECDSASignature ecdsaSig(rawR, rawS);
Poco::DigestEngine::Digest derSig = ecdsaSig.toDER();
Poco::Crypto::ECDSADigestEngine ecdsa(*signer.getECKey(), _digestType);
ecdsa.update(header);
ecdsa.update('.');
ecdsa.update(payload);
return ecdsa.verify(derSig);
}
private:
std::string _digestType;
};
class ES256: public ECDSAAlgorithm
{
public:
ES256():
ECDSAAlgorithm(Algorithm::SHA256)
{
}
};
class ES384: public ECDSAAlgorithm
{
public:
ES384():
ECDSAAlgorithm(Algorithm::SHA384)
{
}
};
class ES512: public ECDSAAlgorithm
{
public:
ES512():
ECDSAAlgorithm(Algorithm::SHA512)
{
}
};
//
// AlgorithmFactory
//
class AlgorithmFactory: public Poco::DynamicFactory<Algorithm>
{
public:
AlgorithmFactory()
{
registerClass<HS256>(Signer::ALGO_HS256);
registerClass<HS384>(Signer::ALGO_HS384);
registerClass<HS512>(Signer::ALGO_HS512);
registerClass<RS256>(Signer::ALGO_RS256);
registerClass<RS384>(Signer::ALGO_RS384);
registerClass<RS512>(Signer::ALGO_RS512);
registerClass<ES256>(Signer::ALGO_ES256);
registerClass<ES384>(Signer::ALGO_ES384);
registerClass<ES512>(Signer::ALGO_ES512);
}
};
//
// Signer
//
const std::string Signer::ALGO_NONE("none");
const std::string Signer::ALGO_HS256("HS256");
const std::string Signer::ALGO_HS384("HS384");
const std::string Signer::ALGO_HS512("HS512");
const std::string Signer::ALGO_RS256("RS256");
const std::string Signer::ALGO_RS384("RS384");
const std::string Signer::ALGO_RS512("RS512");
const std::string Signer::ALGO_ES256("ES256");
const std::string Signer::ALGO_ES384("ES384");
const std::string Signer::ALGO_ES512("ES512");
Signer::Signer()
{
_algorithms.insert(ALGO_HS256);
}
Signer::Signer(const std::string& hmacKey):
_hmacKey(hmacKey)
{
_algorithms.insert(ALGO_HS256);
}
Signer::Signer(const Poco::SharedPtr<Poco::Crypto::RSAKey>& pRSAKey):
_pRSAKey(pRSAKey)
{
_algorithms.insert(ALGO_HS256);
}
Signer::Signer(const Poco::SharedPtr<Poco::Crypto::ECKey>& pECKey):
_pECKey(pECKey)
{
_algorithms.insert(ALGO_HS256);
}
Signer::~Signer()
{
}
Signer& Signer::setAlgorithms(const std::set<std::string>& algorithms)
{
_algorithms = algorithms;
return *this;
}
Signer& Signer::addAlgorithm(const std::string& algorithm)
{
_algorithms.insert(algorithm);
return *this;
}
Signer& Signer::addAllAlgorithms()
{
_algorithms.insert(ALGO_HS256);
_algorithms.insert(ALGO_HS384);
_algorithms.insert(ALGO_HS512);
_algorithms.insert(ALGO_RS256);
_algorithms.insert(ALGO_RS384);
_algorithms.insert(ALGO_RS512);
_algorithms.insert(ALGO_ES256);
_algorithms.insert(ALGO_ES384);
_algorithms.insert(ALGO_ES512);
return *this;
}
Signer& Signer::setHMACKey(const std::string& key)
{
_hmacKey = key;
return *this;
}
Signer& Signer::setRSAKey(const Poco::SharedPtr<Poco::Crypto::RSAKey>& pKey)
{
_pRSAKey = pKey;
return *this;
}
Signer& Signer::setECKey(const Poco::SharedPtr<Poco::Crypto::ECKey>& pKey)
{
_pECKey = pKey;
return *this;
}
std::string Signer::sign(Token& token, const std::string& algorithm) const
{
AlgorithmFactory factory;
if (!factory.isClass(algorithm)) throw UnsupportedAlgorithmException(algorithm);
token.setAlgorithm(algorithm);
std::string header = Serializer::serialize(token.header());
std::string payload = Serializer::serialize(token.payload());
Algorithm::Ptr pAlgorithm = factory.createInstance(algorithm);
Poco::DigestEngine::Digest digest = pAlgorithm->sign(*this, header, payload);
std::string signature = encode(digest);
token.sign(signature);
std::string jwt = header;
jwt += '.';
jwt += payload;
jwt += '.';
jwt += signature;
return jwt;
}
Token Signer::verify(const std::string& jwt) const
{
Token token;
if (tryVerify(jwt, token))
return token;
else
throw SignatureVerificationException();
}
bool Signer::tryVerify(const std::string& jwt, Token& token) const
{
std::vector<std::string> parts = Serializer::split(jwt);
if (parts.size() < 3) throw ParseException("Not a valid JWT", jwt);
token.assign(parts[0], parts[1], parts[2]);
std::string algorithm = token.getAlgorithm();
if (_algorithms.find(algorithm) == _algorithms.end()) throw UnallowedAlgorithmException(algorithm);
AlgorithmFactory factory;
if (!factory.isClass(algorithm)) throw UnsupportedAlgorithmException(algorithm);
Algorithm::Ptr pAlgorithm = factory.createInstance(algorithm);
return pAlgorithm->verify(*this, parts[0], parts[1], decode(parts[2]));
}
std::string Signer::encode(const Poco::DigestEngine::Digest& digest)
{
std::ostringstream stream;
Poco::Base64Encoder encoder(stream, Poco::BASE64_URL_ENCODING | Poco::BASE64_NO_PADDING);
encoder.write(reinterpret_cast<const char*>(&digest[0]), digest.size());
encoder.close();
return stream.str();
}
Poco::DigestEngine::Digest Signer::decode(const std::string& signature)
{
Poco::DigestEngine::Digest digest;
digest.reserve(64);
Poco::MemoryInputStream stream(signature.data(), signature.size());
Poco::Base64Decoder decoder(stream, Poco::BASE64_URL_ENCODING | Poco::BASE64_NO_PADDING);
int ch = decoder.get();
while (ch != -1)
{
digest.push_back(static_cast<unsigned char>(static_cast<unsigned>(ch)));
ch = decoder.get();
}
return digest;
}
} } // namespace Poco::JWT

180
JWT/src/Token.cpp Normal file
View File

@ -0,0 +1,180 @@
//
// Token.cpp
//
// Library: JWT
// Package: JWT
// Module: Token
//
// Copyright (c) 2019, Applied Informatics Software Engineering GmbH.
// and Contributors.
//
// SPDX-License-Identifier: BSL-1.0
//
#include "Poco/JWT/Token.h"
#include "Poco/JWT/Serializer.h"
#include "Poco/JWT/JWTException.h"
namespace Poco {
namespace JWT {
const std::string Token::CLAIM_ISSUER("iss");
const std::string Token::CLAIM_SUBJECT("sub");
const std::string Token::CLAIM_AUDIENCE("aud");
const std::string Token::CLAIM_EXPIRATION("exp");
const std::string Token::CLAIM_NOT_BEFORE("nbf");
const std::string Token::CLAIM_ISSUED_AT("iat");
const std::string Token::CLAIM_JWT_ID("jti");
const std::string Token::CLAIM_TYPE("typ");
const std::string Token::CLAIM_ALGORITHM("alg");
const std::string Token::CLAIM_CONTENT_TYPE("cty");
const std::string Token::EMPTY;
Token::Token():
_pHeader(new Poco::JSON::Object),
_pPayload(new Poco::JSON::Object)
{
}
Token::Token(const std::string& token)
{
std::vector<std::string> parts = Serializer::split(token);
if (parts.size() < 3) throw ParseException("Not a valid JWT", token);
_pHeader = Serializer::deserialize(parts[0]);
_pPayload = Serializer::deserialize(parts[1]);
_signature = parts[2];
}
Token::Token(const Token& token):
_pHeader(new Poco::JSON::Object(*token._pHeader)),
_pPayload(new Poco::JSON::Object(*token._pPayload)),
_signature(token._signature)
{
}
Token::Token(const std::string& header, const std::string& payload, const std::string& signature)
{
assign(header, payload, signature);
}
Token::~Token()
{
}
Token& Token::operator = (const Token& token)
{
if (&token != this)
{
Poco::JSON::Object::Ptr pHeader = new Poco::JSON::Object(*token._pHeader);
Poco::JSON::Object::Ptr pPayload = new Poco::JSON::Object(*token._pPayload);
std::string signature = token._signature;
std::swap(_pHeader, pHeader);
std::swap(_pPayload, pPayload);
std::swap(_signature, signature);
}
return *this;
}
Token& Token::operator = (const std::string& token)
{
std::vector<std::string> parts = Serializer::split(token);
if (parts.size() < 3) throw ParseException("Not a valid JWT", token);
assign(parts[0], parts[1], parts[2]);
return *this;
}
void Token::assign(const std::string& header, const std::string& payload, const std::string& signature)
{
Poco::JSON::Object::Ptr pHeader = Serializer::deserialize(header);
Poco::JSON::Object::Ptr pPayload = Serializer::deserialize(payload);
std::string aSignature = signature;
std::swap(_pHeader, pHeader);
std::swap(_pPayload, pPayload);
std::swap(_signature, aSignature);
}
std::string Token::toString() const
{
std::ostringstream stream;
Serializer::serialize(*_pHeader, stream);
stream << '.';
Serializer::serialize(*_pPayload, stream);
stream << '.';
stream << _signature;
return stream.str();
}
void Token::setAudience(const std::vector<std::string>& audience)
{
Poco::JSON::Array::Ptr pArray = new Poco::JSON::Array;
for (std::vector<std::string>::const_iterator it = audience.begin(); it != audience.end(); ++it)
{
pArray->add(*it);
}
_pPayload->set(CLAIM_AUDIENCE, pArray);
}
std::vector<std::string> Token::getAudience() const
{
std::vector<std::string> result;
if (_pPayload->has(CLAIM_AUDIENCE))
{
if (_pPayload->isArray(CLAIM_AUDIENCE))
{
Poco::JSON::Array::Ptr pArray = _pPayload->getArray(CLAIM_AUDIENCE);
if (pArray)
{
for (unsigned i = 0; i < pArray->size(); i++)
{
result.push_back(pArray->getElement<std::string>(i));
}
}
}
else
{
result.push_back(_pPayload->getValue<std::string>(CLAIM_AUDIENCE));
}
}
return result;
}
void Token::setTimestamp(const std::string& claim, const Poco::Timestamp& ts)
{
double epochSeconds = static_cast<double>(ts.epochMicroseconds())/Poco::Timestamp::resolution();
_pPayload->set(claim, epochSeconds);
}
Poco::Timestamp Token::getTimestamp(const std::string& claim) const
{
double epochSeconds = _pPayload->optValue(claim, 0.0);
Poco::Timestamp::TimeVal tv = epochSeconds*Poco::Timestamp::resolution();
return Poco::Timestamp(tv);
}
void Token::sign(const std::string& signature)
{
_signature = signature;
}
} } // namespace Poco::JWT

View File

@ -0,0 +1,27 @@
# Sources
file(GLOB SRCS_G "src/*.cpp")
POCO_SOURCES_AUTO( TEST_SRCS ${SRCS_G})
# Headers
file(GLOB_RECURSE HDRS_G "src/*.h" )
POCO_HEADERS_AUTO( TEST_SRCS ${HDRS_G})
POCO_SOURCES_AUTO_PLAT( TEST_SRCS OFF
src/WinDriver.cpp
)
POCO_SOURCES_AUTO_PLAT( TEST_SRCS WINCE
src/WinCEDriver.cpp
)
add_executable(JWT-testrunner ${TEST_SRCS} )
if(ANDROID)
add_test(NAME JWT WORKING_DIRECTORY ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}
COMMAND ${CMAKE_COMMAND} -DANDROID_NDK=${ANDROID_NDK} -DLIBRARY_DIR=${CMAKE_BINARY_DIR}/lib -DUNITTEST=${CMAKE_BINARY_DIR}/bin/JWT-testrunner -DTEST_PARAMETER=-all -P ${CMAKE_SOURCE_DIR}/cmake/ExecuteOnAndroid.cmake)
else()
add_test(NAME JWT WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} COMMAND JWT-testrunner -all)
endif()
target_link_libraries(JWT-testrunner PUBLIC Poco::JWT Poco::Crypto CppUnit)
if(UNIX AND NOT ANDROID)
target_link_libraries(JWT-testrunner PUBLIC pthread)
endif(UNIX AND NOT ANDROID)

19
JWT/testsuite/Makefile Normal file
View File

@ -0,0 +1,19 @@
#
# Makefile
#
# Makefile for Poco JWT testsuite
#
include $(POCO_BASE)/build/rules/global
objects = SerializerTest TokenTest SignerTest JWTTestSuite Driver
target = testrunner
target_version = 1
target_libs = PocoJWT PocoJSON PocoCrypto PocoFoundation CppUnit
include $(POCO_BASE)/build/rules/exec
ifdef POCO_UNBUNDLED
SYSLIBS += -lpcre
endif

View File

@ -0,0 +1,17 @@
//
// Driver.cpp
//
// Console-based test driver for Poco JWT.
//
// Copyright (c) 2019, Applied Informatics Software Engineering GmbH.
// and Contributors.
//
// SPDX-License-Identifier: BSL-1.0
//
#include "CppUnit/TestRunner.h"
#include "JWTTestSuite.h"
CppUnitMain(JWTTestSuite)

View File

@ -0,0 +1,26 @@
//
// JWTTestSuite.cpp
//
// Copyright (c) 2019, Applied Informatics Software Engineering GmbH.
// and Contributors.
//
// SPDX-License-Identifier: BSL-1.0
//
#include "JWTTestSuite.h"
#include "SerializerTest.h"
#include "TokenTest.h"
#include "SignerTest.h"
CppUnit::Test* JWTTestSuite::suite()
{
CppUnit::TestSuite* pSuite = new CppUnit::TestSuite("JWTTestSuite");
pSuite->addTest(SerializerTest::suite());
pSuite->addTest(TokenTest::suite());
pSuite->addTest(SignerTest::suite());
return pSuite;
}

View File

@ -0,0 +1,27 @@
//
// JWTTestSuite.h
//
// Definition of the JWTTestSuite class.
//
// Copyright (c) 2019, Applied Informatics Software Engineering GmbH.
// and Contributors.
//
// SPDX-License-Identifier: BSL-1.0
//
#ifndef JWTTestSuite_INCLUDED
#define JWTTestSuite_INCLUDED
#include "CppUnit/TestSuite.h"
class JWTTestSuite
{
public:
static CppUnit::Test* suite();
};
#endif // JWTTestSuite_INCLUDED

View File

@ -0,0 +1,131 @@
//
// SerializerTest.cpp
//
// Copyright (c) 2019, Applied Informatics Software Engineering GmbH.
// and Contributors.
//
// SPDX-License-Identifier: BSL-1.0
//
#include "SerializerTest.h"
#include "CppUnit/TestCaller.h"
#include "CppUnit/TestSuite.h"
#include "Poco/JWT/Serializer.h"
using namespace Poco::JWT;
SerializerTest::SerializerTest(const std::string& name):
CppUnit::TestCase("SerializerTest")
{
}
SerializerTest::~SerializerTest()
{
}
void SerializerTest::setUp()
{
}
void SerializerTest::tearDown()
{
}
void SerializerTest::testSerializeEmpty()
{
Poco::JSON::Object::Ptr pObject = new Poco::JSON::Object;
std::string str = Serializer::serialize(*pObject);
assert (str == "e30");
}
void SerializerTest::testSerializeAlgNone()
{
Poco::JSON::Object::Ptr pObject = new Poco::JSON::Object;
pObject->set("alg", std::string("none"));
std::string str = Serializer::serialize(*pObject);
assert (str == "eyJhbGciOiJub25lIn0");
}
void SerializerTest::testSerializeAlgHS256()
{
Poco::JSON::Object::Ptr pObject = new Poco::JSON::Object;
pObject->set("alg", std::string("HS256"));
pObject->set("typ", std::string("JWT"));
std::string str = Serializer::serialize(*pObject);
assert (str == "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9");
}
void SerializerTest::testDeserializeEmpty()
{
std::string serialized("e30");
Poco::JSON::Object::Ptr pObject = Serializer::deserialize(serialized);
assert (pObject->size() == 0);
}
void SerializerTest::testDeserializeAlgNone()
{
std::string serialized("eyJhbGciOiJub25lIn0");
Poco::JSON::Object::Ptr pObject = Serializer::deserialize(serialized);
assert (pObject->size() == 1);
assert (pObject->getValue<std::string>("alg") == "none");
}
void SerializerTest::testDeserializeAlgHS256()
{
std::string serialized("eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9");
Poco::JSON::Object::Ptr pObject = Serializer::deserialize(serialized);
assert (pObject->size() == 2);
assert (pObject->getValue<std::string>("alg") == "HS256");
assert (pObject->getValue<std::string>("typ") == "JWT");
}
void SerializerTest::testSplit()
{
std::string jwt("eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c");
std::vector<std::string> parts = Serializer::split(jwt);
assert (parts.size() == 3);
assert (parts[0] == "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9");
assert (parts[1] == "eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ");
assert (parts[2] == "SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c");
}
void SerializerTest::testSplitEmptySig()
{
std::string jwt("eyJhbGciOiJub25lIn0.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.");
std::vector<std::string> parts = Serializer::split(jwt);
assert (parts.size() == 3);
assert (parts[0] == "eyJhbGciOiJub25lIn0");
assert (parts[1] == "eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ");
assert (parts[2] == "");
}
CppUnit::Test* SerializerTest::suite()
{
CppUnit::TestSuite* pSuite = new CppUnit::TestSuite("SerializerTest");
CppUnit_addTest(pSuite, SerializerTest, testSerializeEmpty);
CppUnit_addTest(pSuite, SerializerTest, testSerializeAlgNone);
CppUnit_addTest(pSuite, SerializerTest, testSerializeAlgHS256);
CppUnit_addTest(pSuite, SerializerTest, testDeserializeEmpty);
CppUnit_addTest(pSuite, SerializerTest, testDeserializeAlgNone);
CppUnit_addTest(pSuite, SerializerTest, testDeserializeAlgHS256);
CppUnit_addTest(pSuite, SerializerTest, testSplit);
CppUnit_addTest(pSuite, SerializerTest, testSplitEmptySig);
return pSuite;
}

View File

@ -0,0 +1,43 @@
//
// SerializerTest.h
//
// Definition of the SerializerTest class.
//
// Copyright (c) 2019, Applied Informatics Software Engineering GmbH.
// and Contributors.
//
// SPDX-License-Identifier: BSL-1.0
//
#ifndef SerializerTest_INCLUDED
#define SerializerTest_INCLUDED
#include "Poco/JWT/JWT.h"
#include "CppUnit/TestCase.h"
class SerializerTest: public CppUnit::TestCase
{
public:
SerializerTest(const std::string& name);
~SerializerTest();
void setUp();
void tearDown();
void testSerializeEmpty();
void testSerializeAlgNone();
void testSerializeAlgHS256();
void testDeserializeEmpty();
void testDeserializeAlgNone();
void testDeserializeAlgHS256();
void testSplit();
void testSplitEmptySig();
static CppUnit::Test* suite();
};
#endif // SerializerTest_INCLUDED

View File

@ -0,0 +1,466 @@
//
// SignerTest.cpp
//
// Copyright (c) 2019, Applied Informatics Software Engineering GmbH.
// and Contributors.
//
// SPDX-License-Identifier: BSL-1.0
//
#include "SignerTest.h"
#include "CppUnit/TestCaller.h"
#include "CppUnit/TestSuite.h"
#include "Poco/JWT/Signer.h"
#include "Poco/JWT/JWTException.h"
using namespace Poco::JWT;
const std::string SignerTest::RSA_PRIVATE_KEY(
"-----BEGIN RSA PRIVATE KEY-----\n"
"MIIEpQIBAAKCAQEAyVsWBblTS6iuhZiScYwX3Q8O0q2rvbC9cw9fO9NE3XMjzSGf\n"
"NMMFqRRgnivduUvpXwQxw711Va6Y/7o8xrRJ+LBflKBN7EEMdBbNyj7HvZrrkonW\n"
"X/mO1uFo9Tf4Lt0hfomE1tqcXw5IGi4X1wXzvbUvDhFqmFcL3F7alIeSPPoZe5Kq\n"
"4PFoVxhH8z+2u4Q3qME2NbYvJqYaaO+cCxX1JtdY230LL/rHXtH+EbhJpHJNGdLz\n"
"zCJMdKZF3Aqz4J5lb1z6FYIekzJ20FvJ6it1tCQplQisEJyo2YNYCgzBUeAcJoXw\n"
"o4OqsIgfpLWEoTBxm5WbarIwt6yVLRamHGXsZQIDAQABAoIBAQCF5F65gamExu7+\n"
"AR1oCcsYgNnPeBKaeXsQlqkyA+NoChdFYVUXZZNPAjDZHLw8aeEOAKEC0unCBu7Q\n"
"JcwiKWKCzu1PzGTkc8DPNRa0pJh3WRvKfoOhoDW+Z3c+kHAk4YBTPyipIgcXIk0J\n"
"s5rArcGNZXybszMZh9BoQl7Ao4G3rzssIAn4lKhoHPkm4YhJqhboPb0esjTtQXZU\n"
"QIbME3Psir2BgtL+dAW15DofmmvSwVFlsW9tM2QMrS7RtEDoDbEgdteAYGJe+BKg\n"
"6+wH9fGR7Csacqfg5YWBYBC6zwMtOxYIYLuSA3MeWH529M7V26hog/cntl4CA8C4\n"
"Q/vdfjrhAoGBAPzoP7rjkZkwiE49IHLjth7wMEpJJzb9O33jAtRRqz46gXRMO7y2\n"
"lADzHkHmMaJThxtVSQleNHWHW/QZosEaVqw8ibfIeUNVnwLZBL02Rp0XyVnLp2zq\n"
"bG8kQM5CQO9yrckQ4U7hE6Nb9goXR1DzojdllXjS0G2LuGNeZAjL3Pc5AoGBAMvR\n"
"c0UAESCwQX93WyvJRQUsx/3qLWvm84o847W3Ouik4CPxWX6K77lHu8trwl0+sI4r\n"
"+1l4IMli1GBYnp+h64kcIHRcdh8cdB2Q0SSovpbIfBQDmLLxH2eZcPsCkimrRvWw\n"
"1wdPw3e56vn/uhOil1BBqjTdUel4cJkaQX8bDdKNAoGBALxjfGWIcsJ7xm0RV4R9\n"
"XwI4xJ/xUgbCJ3iki00A8OBP0HKC/tSZ5DG458cK49oZAkE4DEmwJL+Pbs2r8vKI\n"
"3hs6lROTf9DKjMIgSklvjrYiK9h5vWOCU/eON7/s1lYHRLDLpCmPu4MqU2I86ODC\n"
"Owms3+S6lIulUlqiyz1KLnTxAoGBAKYrOjY8Krqi2JOKhNs6+bmRW+/o12VMYqwG\n"
"noPNQgrgORk0sQkZTv6YvEPJtCn/bURMGV1FMj3eBFYUiiaNhZFATDlyFJ+ivAxK\n"
"wCiKJvCZvYc3s2vYaAk3sUQEQZQVXwH6TiVY430eJ7PwyQ0vFvxIvPLiqeCV3/8C\n"
"x/lP3kIVAoGAZbiwceB12RTDCL2jsczN4ZE16VyXvatI44NWtakbuxZoDJGhg5Uu\n"
"N2xb6w2mkmaJ0FUi2+B7Vpv8vmH98Aylfev03J4qnJgaNVVEK2nlprkOyflHr7Bj\n"
"fIG0bvyvwUNUy8f5idTqcucDi02zu3Sfr2+LocNUJgrbvswMIXUE3v8=\n"
"-----END RSA PRIVATE KEY-----\n"
);
const std::string SignerTest::RSA_PUBLIC_KEY(
"-----BEGIN PUBLIC KEY-----\n"
"MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAyVsWBblTS6iuhZiScYwX\n"
"3Q8O0q2rvbC9cw9fO9NE3XMjzSGfNMMFqRRgnivduUvpXwQxw711Va6Y/7o8xrRJ\n"
"+LBflKBN7EEMdBbNyj7HvZrrkonWX/mO1uFo9Tf4Lt0hfomE1tqcXw5IGi4X1wXz\n"
"vbUvDhFqmFcL3F7alIeSPPoZe5Kq4PFoVxhH8z+2u4Q3qME2NbYvJqYaaO+cCxX1\n"
"JtdY230LL/rHXtH+EbhJpHJNGdLzzCJMdKZF3Aqz4J5lb1z6FYIekzJ20FvJ6it1\n"
"tCQplQisEJyo2YNYCgzBUeAcJoXwo4OqsIgfpLWEoTBxm5WbarIwt6yVLRamHGXs\n"
"ZQIDAQAB\n"
"-----END PUBLIC KEY-----\n"
);
const std::string SignerTest::ECDSA_PRIVATE_KEY(
"-----BEGIN PRIVATE KEY-----\n"
"MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgevZzL1gdAFr88hb2\n"
"OF/2NxApJCzGCEDdfSp6VQO30hyhRANCAAQRWz+jn65BtOMvdyHKcvjBeBSDZH2r\n"
"1RTwjmYSi9R/zpBnuQ4EiMnCqfMPWiZqB4QdbAd0E7oH50VpuZ1P087G\n"
"-----END PRIVATE KEY-----\n"
);
const std::string SignerTest::ECDSA_PUBLIC_KEY(
"-----BEGIN PUBLIC KEY-----\n"
"MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEEVs/o5+uQbTjL3chynL4wXgUg2R9\n"
"q9UU8I5mEovUf86QZ7kOBIjJwqnzD1omageEHWwHdBO6B+dFabmdT9POxg==\n"
"-----END PUBLIC KEY-----\n"
);
SignerTest::SignerTest(const std::string& name):
CppUnit::TestCase("SignerTest")
{
}
SignerTest::~SignerTest()
{
}
void SignerTest::setUp()
{
}
void SignerTest::tearDown()
{
}
void SignerTest::testSignHS256()
{
Token token;
token.setType("JWT");
token.setSubject("1234567890");
token.payload().set("name", std::string("John Doe"));
token.setIssuedAt(Poco::Timestamp::fromEpochTime(1516239022));
Signer signer("0123456789ABCDEF0123456789ABCDEF");
std::string jwt = signer.sign(token, Signer::ALGO_HS256);
assert (jwt == "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpYXQiOjE1MTYyMzkwMjIsIm5hbWUiOiJKb2huIERvZSIsInN1YiI6IjEyMzQ1Njc4OTAifQ.qn9G7NwFEOjIh-7hfCUDZA1aJeQmf7I7YvzCBcdenGw");
}
void SignerTest::testSignHS384()
{
Token token;
token.setType("JWT");
token.setSubject("1234567890");
token.payload().set("name", std::string("John Doe"));
token.setIssuedAt(Poco::Timestamp::fromEpochTime(1516239022));
Signer signer("0123456789ABCDEF0123456789ABCDEF");
std::string jwt = signer.sign(token, Signer::ALGO_HS384);
assert (jwt == "eyJhbGciOiJIUzM4NCIsInR5cCI6IkpXVCJ9.eyJpYXQiOjE1MTYyMzkwMjIsIm5hbWUiOiJKb2huIERvZSIsInN1YiI6IjEyMzQ1Njc4OTAifQ.9NsI7ahPhCd3itTewXb0GNZi08fuUHXLx0qeBscteMXJiug1PyQ_teA9v7zLgg1W");
}
void SignerTest::testSignHS512()
{
Token token;
token.setType("JWT");
token.setSubject("1234567890");
token.payload().set("name", std::string("John Doe"));
token.setIssuedAt(Poco::Timestamp::fromEpochTime(1516239022));
Signer signer("0123456789ABCDEF0123456789ABCDEF");
std::string jwt = signer.sign(token, Signer::ALGO_HS512);
assert (jwt == "eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9.eyJpYXQiOjE1MTYyMzkwMjIsIm5hbWUiOiJKb2huIERvZSIsInN1YiI6IjEyMzQ1Njc4OTAifQ.WG4y8U_bDN4T3Vu3L5Q5C4pqssrH4wqBtdrFLVuS8k-BLycCq8_bjYGgo7BCzVt4DFXs3BFUIJQdWBzuJwXHtg");
}
void SignerTest::testVerifyHS256()
{
std::string jwt("eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpYXQiOjE1MTYyMzkwMjIsIm5hbWUiOiJKb2huIERvZSIsInN1YiI6IjEyMzQ1Njc4OTAifQ.qn9G7NwFEOjIh-7hfCUDZA1aJeQmf7I7YvzCBcdenGw");
Signer signer("0123456789ABCDEF0123456789ABCDEF");
try
{
Token token = signer.verify(jwt);
assert (token.getAlgorithm() == "HS256");
assert (token.getType() == "JWT");
assert (token.getSubject() == "1234567890");
assert (token.getIssuedAt().epochTime() == 1516239022);
assert (token.payload().getValue<std::string>("name") == "John Doe");
assert (token.signature() == "qn9G7NwFEOjIh-7hfCUDZA1aJeQmf7I7YvzCBcdenGw");
}
catch (JWTException&)
{
fail("Verification must succeed");
}
}
void SignerTest::testVerifyHS384()
{
std::string jwt("eyJhbGciOiJIUzM4NCIsInR5cCI6IkpXVCJ9.eyJpYXQiOjE1MTYyMzkwMjIsIm5hbWUiOiJKb2huIERvZSIsInN1YiI6IjEyMzQ1Njc4OTAifQ.9NsI7ahPhCd3itTewXb0GNZi08fuUHXLx0qeBscteMXJiug1PyQ_teA9v7zLgg1W");
Signer signer("0123456789ABCDEF0123456789ABCDEF");
signer.addAlgorithm(Signer::ALGO_HS384);
try
{
Token token = signer.verify(jwt);
assert (token.getAlgorithm() == "HS384");
assert (token.getType() == "JWT");
assert (token.getSubject() == "1234567890");
assert (token.getIssuedAt().epochTime() == 1516239022);
assert (token.payload().getValue<std::string>("name") == "John Doe");
assert (token.signature() == "9NsI7ahPhCd3itTewXb0GNZi08fuUHXLx0qeBscteMXJiug1PyQ_teA9v7zLgg1W");
}
catch (JWTException&)
{
fail("Verification must succeed");
}
}
void SignerTest::testVerifyHS512()
{
std::string jwt("eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9.eyJpYXQiOjE1MTYyMzkwMjIsIm5hbWUiOiJKb2huIERvZSIsInN1YiI6IjEyMzQ1Njc4OTAifQ.WG4y8U_bDN4T3Vu3L5Q5C4pqssrH4wqBtdrFLVuS8k-BLycCq8_bjYGgo7BCzVt4DFXs3BFUIJQdWBzuJwXHtg");
Signer signer("0123456789ABCDEF0123456789ABCDEF");
signer.addAlgorithm(Signer::ALGO_HS512);
try
{
Token token = signer.verify(jwt);
assert (token.getAlgorithm() == "HS512");
assert (token.getType() == "JWT");
assert (token.getSubject() == "1234567890");
assert (token.getIssuedAt().epochTime() == 1516239022);
assert (token.payload().getValue<std::string>("name") == "John Doe");
assert (token.signature() == "WG4y8U_bDN4T3Vu3L5Q5C4pqssrH4wqBtdrFLVuS8k-BLycCq8_bjYGgo7BCzVt4DFXs3BFUIJQdWBzuJwXHtg");
}
catch (JWTException&)
{
fail("Verification must succeed");
}
}
void SignerTest::testVerifyFailSignature()
{
std::string jwt("eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpYXQiOjE1MTYyMzkwMjIsIm5hbWUiOiJKb2huIERvZSIsInN1YiI6IjEyMzQ1Njc4OTAifQ.wn9G7NwFEOjIh-7hfCFDZA1aJeQmf7I7YvzCBcdenGw");
Signer signer("0123456789ABCDEF0123456789ABCDEF");
try
{
Token token = signer.verify(jwt);
fail("Verification must fail");
}
catch (SignatureVerificationException&)
{
}
}
void SignerTest::testVerifyFailKey()
{
std::string jwt("eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpYXQiOjE1MTYyMzkwMjIsIm5hbWUiOiJKb2huIERvZSIsInN1YiI6IjEyMzQ1Njc4OTAifQ.qn9G7NwFEOjIh-7hfCUDZA1aJeQmf7I7YvzCBcdenGw");
Signer signer("0123456789ABCDEF0123456789ABFAIL");
try
{
Token token = signer.verify(jwt);
fail("Verification must fail");
}
catch (SignatureVerificationException&)
{
}
}
void SignerTest::testSignRS256()
{
Token token;
token.setType("JWT");
token.setSubject("1234567890");
token.payload().set("name", std::string("John Doe"));
token.setIssuedAt(Poco::Timestamp::fromEpochTime(1516239022));
std::istringstream privateKeyStream(RSA_PRIVATE_KEY);
Poco::SharedPtr<Poco::Crypto::RSAKey> pKey = new Poco::Crypto::RSAKey(0, &privateKeyStream);
Signer signer(pKey);
std::string jwt = signer.sign(token, Signer::ALGO_RS256);
assert (jwt == "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJpYXQiOjE1MTYyMzkwMjIsIm5hbWUiOiJKb2huIERvZSIsInN1YiI6IjEyMzQ1Njc4OTAifQ.a27BSSEBTaQZFA1tVX4IZHgyG5HIXcJVZpbpB5LQ_rPTalJjvhDDuWC1dM0G0tUACrzPtUN4BhSd-dygJsX4b35DnWm_gPUNDI3HMm7Ck52mM_2Y6445B6aa_pPPuFk6AWql8WWLzQqo9kjQh8AmbMw2A9bciA1smEEsHVw4-VX1tEtupbhJsXO2FnwkQNhJF_Pp4nuX282UV_4DtZ9LW3jLoEYFytKrM4fhkNKVMY52Cn0DJA89fQYe7098gduCjzqoGtaoKKDngbADn2h_1P8VLZrZEd4UROEHviVLm_qxHrWY8-tB0L7i_JMXxw1qMKAavWA-WbnNDdXpOn_o2Q");
}
void SignerTest::testSignRS384()
{
Token token;
token.setType("JWT");
token.setSubject("1234567890");
token.payload().set("name", std::string("John Doe"));
token.setIssuedAt(Poco::Timestamp::fromEpochTime(1516239022));
std::istringstream privateKeyStream(RSA_PRIVATE_KEY);
Poco::SharedPtr<Poco::Crypto::RSAKey> pKey = new Poco::Crypto::RSAKey(0, &privateKeyStream);
Signer signer(pKey);
std::string jwt = signer.sign(token, Signer::ALGO_RS384);
assert (jwt == "eyJhbGciOiJSUzM4NCIsInR5cCI6IkpXVCJ9.eyJpYXQiOjE1MTYyMzkwMjIsIm5hbWUiOiJKb2huIERvZSIsInN1YiI6IjEyMzQ1Njc4OTAifQ.L-34N4v5kLa94Llz-XakGIwL9M00ERciAzZSqxgGIJ2dw9VrIodfK-U00wZZwSA2UEZWIm-LJ7wQBiuUw8oMl_fYsufT8W6dWiGZQ2c24AjGKwpXmypPKjh5yRnylkK-8ZRC1AJuZDsY8DJE7vse1w2eAE_Jw0XRJ-u_lq9Hgxz58ZonV1YzUdyVPtD3gWdhyjnlzPCH7lQM4copVUFN6mFTZzt4WQ2i1O1qW1cD_F4Jul9_5z5BYe7-bK3DoV79AgfbEewdnc4yatLQWMIAkrc2LM_tFe83ABhFYhM0qIH8nOuk3WKyKwtjh15f3h3Fn-JnriSfcC79v-M5UpEsZg");
}
void SignerTest::testSignRS512()
{
Token token;
token.setType("JWT");
token.setSubject("1234567890");
token.payload().set("name", std::string("John Doe"));
token.setIssuedAt(Poco::Timestamp::fromEpochTime(1516239022));
std::istringstream privateKeyStream(RSA_PRIVATE_KEY);
Poco::SharedPtr<Poco::Crypto::RSAKey> pKey = new Poco::Crypto::RSAKey(0, &privateKeyStream);
Signer signer(pKey);
std::string jwt = signer.sign(token, Signer::ALGO_RS512);
assert (jwt == "eyJhbGciOiJSUzUxMiIsInR5cCI6IkpXVCJ9.eyJpYXQiOjE1MTYyMzkwMjIsIm5hbWUiOiJKb2huIERvZSIsInN1YiI6IjEyMzQ1Njc4OTAifQ.XQTBYo2zqxcyUGs0H-74tfBY6l8PxBQK7-IAJ1NgEVIeoMDX3zQJu5BQX2_VhjOESOPqGNN-FtiNLD1G-LCvSV1fxJwIVEilT7CTBs5iNii6Jrpha5YPnzETqBiz1zdnyNh_QVbtdRIv2ORlp_OIYNZJrxiRfOGvm2_Z3htDoqgv_Lm8SZqelOntox96GrV6GaXhpKBbLjBSU-XPkSOcm5VuXDCz8tltJ_d5cKxbFDUtS6FBYNMaLEqIL4-_aJU_Ld5TcPQT7MqWlHHZZufA5zzmfKEEgddco6uzCBLOz3B6E4Z5VZDoweCM5R7hnLiZOlK0kYsFoaDCVcK_TZhDNw");
}
void SignerTest::testVerifyRS256()
{
std::string jwt("eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJpYXQiOjE1MTYyMzkwMjIsIm5hbWUiOiJKb2huIERvZSIsInN1YiI6IjEyMzQ1Njc4OTAifQ.a27BSSEBTaQZFA1tVX4IZHgyG5HIXcJVZpbpB5LQ_rPTalJjvhDDuWC1dM0G0tUACrzPtUN4BhSd-dygJsX4b35DnWm_gPUNDI3HMm7Ck52mM_2Y6445B6aa_pPPuFk6AWql8WWLzQqo9kjQh8AmbMw2A9bciA1smEEsHVw4-VX1tEtupbhJsXO2FnwkQNhJF_Pp4nuX282UV_4DtZ9LW3jLoEYFytKrM4fhkNKVMY52Cn0DJA89fQYe7098gduCjzqoGtaoKKDngbADn2h_1P8VLZrZEd4UROEHviVLm_qxHrWY8-tB0L7i_JMXxw1qMKAavWA-WbnNDdXpOn_o2Q");
std::istringstream publicKeyStream(RSA_PUBLIC_KEY);
Poco::SharedPtr<Poco::Crypto::RSAKey> pKey = new Poco::Crypto::RSAKey(&publicKeyStream);
Signer signer(pKey);
signer.addAlgorithm(Signer::ALGO_RS256);
try
{
Token token = signer.verify(jwt);
assert (token.getAlgorithm() == "RS256");
assert (token.getType() == "JWT");
assert (token.getSubject() == "1234567890");
assert (token.getIssuedAt().epochTime() == 1516239022);
assert (token.payload().getValue<std::string>("name") == "John Doe");
assert (token.signature() == "a27BSSEBTaQZFA1tVX4IZHgyG5HIXcJVZpbpB5LQ_rPTalJjvhDDuWC1dM0G0tUACrzPtUN4BhSd-dygJsX4b35DnWm_gPUNDI3HMm7Ck52mM_2Y6445B6aa_pPPuFk6AWql8WWLzQqo9kjQh8AmbMw2A9bciA1smEEsHVw4-VX1tEtupbhJsXO2FnwkQNhJF_Pp4nuX282UV_4DtZ9LW3jLoEYFytKrM4fhkNKVMY52Cn0DJA89fQYe7098gduCjzqoGtaoKKDngbADn2h_1P8VLZrZEd4UROEHviVLm_qxHrWY8-tB0L7i_JMXxw1qMKAavWA-WbnNDdXpOn_o2Q");
}
catch (JWTException&)
{
fail("Verification must succeed");
}
}
void SignerTest::testVerifyRS384()
{
std::string jwt("eyJhbGciOiJSUzM4NCIsInR5cCI6IkpXVCJ9.eyJpYXQiOjE1MTYyMzkwMjIsIm5hbWUiOiJKb2huIERvZSIsInN1YiI6IjEyMzQ1Njc4OTAifQ.L-34N4v5kLa94Llz-XakGIwL9M00ERciAzZSqxgGIJ2dw9VrIodfK-U00wZZwSA2UEZWIm-LJ7wQBiuUw8oMl_fYsufT8W6dWiGZQ2c24AjGKwpXmypPKjh5yRnylkK-8ZRC1AJuZDsY8DJE7vse1w2eAE_Jw0XRJ-u_lq9Hgxz58ZonV1YzUdyVPtD3gWdhyjnlzPCH7lQM4copVUFN6mFTZzt4WQ2i1O1qW1cD_F4Jul9_5z5BYe7-bK3DoV79AgfbEewdnc4yatLQWMIAkrc2LM_tFe83ABhFYhM0qIH8nOuk3WKyKwtjh15f3h3Fn-JnriSfcC79v-M5UpEsZg");
std::istringstream publicKeyStream(RSA_PUBLIC_KEY);
Poco::SharedPtr<Poco::Crypto::RSAKey> pKey = new Poco::Crypto::RSAKey(&publicKeyStream);
Signer signer(pKey);
signer.addAlgorithm(Signer::ALGO_RS384);
try
{
Token token = signer.verify(jwt);
assert (token.getAlgorithm() == "RS384");
assert (token.getType() == "JWT");
assert (token.getSubject() == "1234567890");
assert (token.getIssuedAt().epochTime() == 1516239022);
assert (token.payload().getValue<std::string>("name") == "John Doe");
assert (token.signature() == "L-34N4v5kLa94Llz-XakGIwL9M00ERciAzZSqxgGIJ2dw9VrIodfK-U00wZZwSA2UEZWIm-LJ7wQBiuUw8oMl_fYsufT8W6dWiGZQ2c24AjGKwpXmypPKjh5yRnylkK-8ZRC1AJuZDsY8DJE7vse1w2eAE_Jw0XRJ-u_lq9Hgxz58ZonV1YzUdyVPtD3gWdhyjnlzPCH7lQM4copVUFN6mFTZzt4WQ2i1O1qW1cD_F4Jul9_5z5BYe7-bK3DoV79AgfbEewdnc4yatLQWMIAkrc2LM_tFe83ABhFYhM0qIH8nOuk3WKyKwtjh15f3h3Fn-JnriSfcC79v-M5UpEsZg");
}
catch (JWTException&)
{
fail("Verification must succeed");
}
}
void SignerTest::testVerifyRS512()
{
std::string jwt("eyJhbGciOiJSUzUxMiIsInR5cCI6IkpXVCJ9.eyJpYXQiOjE1MTYyMzkwMjIsIm5hbWUiOiJKb2huIERvZSIsInN1YiI6IjEyMzQ1Njc4OTAifQ.XQTBYo2zqxcyUGs0H-74tfBY6l8PxBQK7-IAJ1NgEVIeoMDX3zQJu5BQX2_VhjOESOPqGNN-FtiNLD1G-LCvSV1fxJwIVEilT7CTBs5iNii6Jrpha5YPnzETqBiz1zdnyNh_QVbtdRIv2ORlp_OIYNZJrxiRfOGvm2_Z3htDoqgv_Lm8SZqelOntox96GrV6GaXhpKBbLjBSU-XPkSOcm5VuXDCz8tltJ_d5cKxbFDUtS6FBYNMaLEqIL4-_aJU_Ld5TcPQT7MqWlHHZZufA5zzmfKEEgddco6uzCBLOz3B6E4Z5VZDoweCM5R7hnLiZOlK0kYsFoaDCVcK_TZhDNw");
std::istringstream publicKeyStream(RSA_PUBLIC_KEY);
Poco::SharedPtr<Poco::Crypto::RSAKey> pKey = new Poco::Crypto::RSAKey(&publicKeyStream);
Signer signer(pKey);
signer.addAlgorithm(Signer::ALGO_RS512);
try
{
Token token = signer.verify(jwt);
assert (token.getAlgorithm() == "RS512");
assert (token.getType() == "JWT");
assert (token.getSubject() == "1234567890");
assert (token.getIssuedAt().epochTime() == 1516239022);
assert (token.payload().getValue<std::string>("name") == "John Doe");
assert (token.signature() == "XQTBYo2zqxcyUGs0H-74tfBY6l8PxBQK7-IAJ1NgEVIeoMDX3zQJu5BQX2_VhjOESOPqGNN-FtiNLD1G-LCvSV1fxJwIVEilT7CTBs5iNii6Jrpha5YPnzETqBiz1zdnyNh_QVbtdRIv2ORlp_OIYNZJrxiRfOGvm2_Z3htDoqgv_Lm8SZqelOntox96GrV6GaXhpKBbLjBSU-XPkSOcm5VuXDCz8tltJ_d5cKxbFDUtS6FBYNMaLEqIL4-_aJU_Ld5TcPQT7MqWlHHZZufA5zzmfKEEgddco6uzCBLOz3B6E4Z5VZDoweCM5R7hnLiZOlK0kYsFoaDCVcK_TZhDNw");
}
catch (JWTException&)
{
fail("Verification must succeed");
}
}
void SignerTest::testSignVerifyES256()
{
// Note: ECDSA is a strange beast and does not return a "known" signature.
// That's why we do the signing and verification in a single test.
Token token;
token.setType("JWT");
token.setSubject("1234567890");
token.payload().set("name", std::string("John Doe"));
token.setIssuedAt(Poco::Timestamp::fromEpochTime(1516239022));
std::istringstream privateKeyStream(ECDSA_PRIVATE_KEY);
Poco::SharedPtr<Poco::Crypto::ECKey> pKey = new Poco::Crypto::ECKey(0, &privateKeyStream);
Signer signer(pKey);
std::string jwt = signer.sign(token, Signer::ALGO_ES256);
std::istringstream publicKeyStream(ECDSA_PUBLIC_KEY);
pKey = new Poco::Crypto::ECKey(&publicKeyStream);
Signer verifier(pKey);
verifier.addAlgorithm(Signer::ALGO_ES256);
try
{
Token token2 = verifier.verify(jwt);
assert (token2.getAlgorithm() == "ES256");
assert (token2.getType() == "JWT");
assert (token2.getSubject() == "1234567890");
assert (token2.getIssuedAt().epochTime() == 1516239022);
assert (token2.payload().getValue<std::string>("name") == "John Doe");
}
catch (JWTException&)
{
fail("Verification must succeed");
}
}
void SignerTest::testVerifyES256()
{
std::string jwt("eyJhbGciOiJFUzI1NiIsInR5cCI6IkpXVCJ9.eyJpYXQiOjE1MTYyMzkwMjIsIm5hbWUiOiJKb2huIERvZSIsInN1YiI6IjEyMzQ1Njc4OTAifQ.kLfRdCmR-qewMgzhCtqJrXVoagoh7es0yWsn3VunuS51FMBBcxLTKRDfdgHih0os4gvBdLMYkJu61_IQqoIYZw");
std::istringstream publicKeyStream(ECDSA_PUBLIC_KEY);
Poco::SharedPtr<Poco::Crypto::ECKey> pKey = new Poco::Crypto::ECKey(&publicKeyStream);
Signer signer(pKey);
signer.addAlgorithm(Signer::ALGO_ES256);
try
{
Token token = signer.verify(jwt);
assert (token.getAlgorithm() == "ES256");
assert (token.getType() == "JWT");
assert (token.getSubject() == "1234567890");
assert (token.getIssuedAt().epochTime() == 1516239022);
assert (token.payload().getValue<std::string>("name") == "John Doe");
assert (token.signature() == "kLfRdCmR-qewMgzhCtqJrXVoagoh7es0yWsn3VunuS51FMBBcxLTKRDfdgHih0os4gvBdLMYkJu61_IQqoIYZw");
}
catch (JWTException&)
{
fail("Verification must succeed");
}
}
CppUnit::Test* SignerTest::suite()
{
CppUnit::TestSuite* pSuite = new CppUnit::TestSuite("SignerTest");
CppUnit_addTest(pSuite, SignerTest, testSignHS256);
CppUnit_addTest(pSuite, SignerTest, testSignHS384);
CppUnit_addTest(pSuite, SignerTest, testSignHS512);
CppUnit_addTest(pSuite, SignerTest, testVerifyHS256);
CppUnit_addTest(pSuite, SignerTest, testVerifyHS384);
CppUnit_addTest(pSuite, SignerTest, testVerifyHS512);
CppUnit_addTest(pSuite, SignerTest, testVerifyFailSignature);
CppUnit_addTest(pSuite, SignerTest, testVerifyFailKey);
CppUnit_addTest(pSuite, SignerTest, testSignRS256);
CppUnit_addTest(pSuite, SignerTest, testSignRS384);
CppUnit_addTest(pSuite, SignerTest, testSignRS512);
CppUnit_addTest(pSuite, SignerTest, testVerifyRS256);
CppUnit_addTest(pSuite, SignerTest, testVerifyRS384);
CppUnit_addTest(pSuite, SignerTest, testVerifyRS512);
CppUnit_addTest(pSuite, SignerTest, testSignVerifyES256);
CppUnit_addTest(pSuite, SignerTest, testVerifyES256);
return pSuite;
}

View File

@ -0,0 +1,57 @@
//
// SignerTest.h
//
// Definition of the SignerTest class.
//
// Copyright (c) 2019, Applied Informatics Software Engineering GmbH.
// and Contributors.
//
// SPDX-License-Identifier: BSL-1.0
//
#ifndef SignerTest_INCLUDED
#define SignerTest_INCLUDED
#include "Poco/JWT/JWT.h"
#include "CppUnit/TestCase.h"
class SignerTest: public CppUnit::TestCase
{
public:
SignerTest(const std::string& name);
~SignerTest();
void setUp();
void tearDown();
void testSignHS256();
void testSignHS384();
void testSignHS512();
void testVerifyHS256();
void testVerifyHS384();
void testVerifyHS512();
void testVerifyFailSignature();
void testVerifyFailKey();
void testSignRS256();
void testSignRS384();
void testSignRS512();
void testVerifyRS256();
void testVerifyRS384();
void testVerifyRS512();
void testSignVerifyES256();
void testVerifyES256();
static CppUnit::Test* suite();
static const std::string RSA_PRIVATE_KEY;
static const std::string RSA_PUBLIC_KEY;
static const std::string ECDSA_PRIVATE_KEY;
static const std::string ECDSA_PUBLIC_KEY;
};
#endif // SignerTest_INCLUDED

View File

@ -0,0 +1,127 @@
//
// TokenTest.cpp
//
// Copyright (c) 2019, Applied Informatics Software Engineering GmbH.
// and Contributors.
//
// SPDX-License-Identifier: BSL-1.0
//
#include "TokenTest.h"
#include "CppUnit/TestCaller.h"
#include "CppUnit/TestSuite.h"
#include "Poco/JWT/Token.h"
#include <iostream>
using namespace Poco::JWT;
TokenTest::TokenTest(const std::string& name):
CppUnit::TestCase("TokenTest")
{
}
TokenTest::~TokenTest()
{
}
void TokenTest::setUp()
{
}
void TokenTest::tearDown()
{
}
void TokenTest::testParse()
{
std::string jwt("eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c");
Token token(jwt);
assert (token.getAlgorithm() == "HS256");
assert (token.getType() == "JWT");
assert (token.getSubject() == "1234567890");
assert (token.getIssuedAt().epochTime() == 1516239022);
assert (token.payload().getValue<std::string>("name") == "John Doe");
assert (token.signature() == "SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c");
}
void TokenTest::testParseNoSig()
{
std::string jwt("eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpYXQiOjE1MTYyMzkwMjIsIm5hbWUiOiJKb2huIERvZSIsInN1YiI6IjEyMzQ1Njc4OTAifQ.");
Token token(jwt);
assert (token.getAlgorithm() == "HS256");
assert (token.getType() == "JWT");
assert (token.getSubject() == "1234567890");
assert (token.getIssuedAt().epochTime() == 1516239022);
assert (token.payload().getValue<std::string>("name") == "John Doe");
assert (token.signature() == "");
}
void TokenTest::testSerialize()
{
Token token;
token.setAlgorithm("HS256");
token.setType("JWT");
token.setSubject("1234567890");
token.payload().set("name", std::string("John Doe"));
token.setIssuedAt(Poco::Timestamp::fromEpochTime(1516239022));
std::string jwt = token.toString();
assert (jwt == "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpYXQiOjE1MTYyMzkwMjIsIm5hbWUiOiJKb2huIERvZSIsInN1YiI6IjEyMzQ1Njc4OTAifQ.");
}
void TokenTest::testAssign()
{
std::string jwt("eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c");
Token token(jwt);
Token token2(token);
assert (token.toString() == token2.toString());
}
void TokenTest::testAudience()
{
Token token;
token.setAudience("11111");
assert (token.payload().getValue<std::string>(Token::CLAIM_AUDIENCE) == "11111");
std::vector<std::string> audience = token.getAudience();
assert (audience.size() == 1);
assert (audience[0] == "11111");
audience.push_back("22222");
token.setAudience(audience);
assert (token.payload().isArray(Token::CLAIM_AUDIENCE));
audience = token.getAudience();
assert (audience.size() == 2);
assert (audience[0] == "11111");
assert (audience[1] == "22222");
}
CppUnit::Test* TokenTest::suite()
{
CppUnit::TestSuite* pSuite = new CppUnit::TestSuite("TokenTest");
CppUnit_addTest(pSuite, TokenTest, testParse);
CppUnit_addTest(pSuite, TokenTest, testParseNoSig);
CppUnit_addTest(pSuite, TokenTest, testSerialize);
CppUnit_addTest(pSuite, TokenTest, testAssign);
CppUnit_addTest(pSuite, TokenTest, testAudience);
return pSuite;
}

View File

@ -0,0 +1,40 @@
//
// TokenTest.h
//
// Definition of the TokenTest class.
//
// Copyright (c) 2019, Applied Informatics Software Engineering GmbH.
// and Contributors.
//
// SPDX-License-Identifier: BSL-1.0
//
#ifndef TokenTest_INCLUDED
#define TokenTest_INCLUDED
#include "Poco/JWT/JWT.h"
#include "CppUnit/TestCase.h"
class TokenTest: public CppUnit::TestCase
{
public:
TokenTest(const std::string& name);
~TokenTest();
void setUp();
void tearDown();
void testParse();
void testParseNoSig();
void testSerialize();
void testAssign();
void testAudience();
static CppUnit::Test* suite();
};
#endif // TokenTest_INCLUDED

View File

@ -0,0 +1,30 @@
//
// WinCEDriver.cpp
//
// Console-based test driver for Windows CE.
//
// Copyright (c) 2019, Applied Informatics Software Engineering GmbH.
// and Contributors.
//
// SPDX-License-Identifier: BSL-1.0
//
#include "CppUnit/TestRunner.h"
#include "JWTTestSuite.h"
#include <cstdlib>
int wmain(int argc, wchar_t* argv[])
{
std::vector<std::string> args;
for (int i = 0; i < argc; ++i)
{
char buffer[1024];
std::wcstombs(buffer, argv[i], sizeof(buffer));
args.push_back(std::string(buffer));
}
CppUnit::TestRunner runner;
runner.addTest("JWTTestSuite", JWTTestSuite::suite());
return runner.run(args) ? 0 : 1;
}

View File

@ -0,0 +1,28 @@
//
// WinDriver.cpp
//
// Windows test driver for Poco JWT.
//
// Copyright (c) 2019, Applied Informatics Software Engineering GmbH.
// and Contributors.
//
// SPDX-License-Identifier: BSL-1.0
//
#include "WinTestRunner/WinTestRunner.h"
#include "JWTTestSuite.h"
class TestDriver: public CppUnit::WinTestRunnerApp
{
void TestMain()
{
CppUnit::WinTestRunner runner;
runner.addTest(JWTTestSuite::suite());
runner.run();
}
};
TestDriver theDriver;

View File

@ -16,6 +16,7 @@ Data/PostgreSQL
Zip
PageCompiler
PageCompiler/File2Page
JWT
PDF
CppParser
MongoDB