Add tests. Cleanup formatting.
This commit is contained in:
parent
5ef2e0b929
commit
0b4a73e2b7
|
|
@ -16,6 +16,6 @@ ConstructorInitializerIndentWidth: 4
|
||||||
ContinuationIndentWidth: 4
|
ContinuationIndentWidth: 4
|
||||||
DerivePointerAlignment: false
|
DerivePointerAlignment: false
|
||||||
IndentWidth: 4
|
IndentWidth: 4
|
||||||
PointerAlignment: Middle
|
PointerAlignment: Right
|
||||||
ReflowComments: false
|
ReflowComments: false
|
||||||
...
|
...
|
||||||
|
|
|
||||||
|
|
@ -41,7 +41,11 @@ if(BUILD_TESTING)
|
||||||
|
|
||||||
enable_testing()
|
enable_testing()
|
||||||
|
|
||||||
add_executable(authorizer_test test/authorizer_test.cpp)
|
add_executable(token_test test/token_test.cpp)
|
||||||
target_link_libraries(authorizer_test GTest::gtest_main)
|
target_include_directories(token_test PUBLIC
|
||||||
gtest_discover_tests(authorizer_test)
|
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
|
||||||
|
$<INSTALL_INTERFACE:include>
|
||||||
|
)
|
||||||
|
target_link_libraries(token_test utils GTest::gtest_main)
|
||||||
|
gtest_discover_tests(token_test)
|
||||||
endif()
|
endif()
|
||||||
|
|
|
||||||
|
|
@ -25,15 +25,15 @@ extern "C"
|
||||||
// Stuff we're "exporting" for the dynamic loading.
|
// Stuff we're "exporting" for the dynamic loading.
|
||||||
extern "C"
|
extern "C"
|
||||||
{
|
{
|
||||||
int mosquitto_plugin_version(int supported_version_count, const int * supported_versions);
|
int mosquitto_plugin_version(int supported_version_count, const int *supported_versions);
|
||||||
int mosquitto_plugin_init(
|
int mosquitto_plugin_init(
|
||||||
mosquitto_plugin_id_t * identifier,
|
mosquitto_plugin_id_t *identifier,
|
||||||
void ** userdata,
|
void **userdata,
|
||||||
struct mosquitto_opt * options,
|
struct mosquitto_opt *options,
|
||||||
int option_count);
|
int option_count);
|
||||||
int mosquitto_plugin_cleanup(void * userdata, struct mosquitto_opt * options, int option_count);
|
int mosquitto_plugin_cleanup(void *userdata, struct mosquitto_opt *options, int option_count);
|
||||||
}
|
}
|
||||||
// My functions
|
// My functions
|
||||||
int j7s_auth_basic_auth_callback(int event, void * event_data, void * userdata);
|
int j7s_auth_basic_auth_callback(int event, void *event_data, void *userdata);
|
||||||
int j7s_acl_check_callback(int event, void * event_data, void * userdata);
|
int j7s_acl_check_callback(int event, void *event_data, void *userdata);
|
||||||
int j7s_disconnect_callback(int event, void * event_data, void * userdata);
|
int j7s_disconnect_callback(int event, void *event_data, void *userdata);
|
||||||
|
|
|
||||||
|
|
@ -17,17 +17,14 @@
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <tuple>
|
#include <tuple>
|
||||||
|
|
||||||
std::optional<std::string> read_key(const std::string & key_file);
|
std::optional<std::string> read_key(const std::string &key_file);
|
||||||
|
|
||||||
std::tuple<bool, std::chrono::time_point<std::chrono::system_clock>> validate(
|
std::tuple<bool, std::chrono::time_point<std::chrono::system_clock>> validate(
|
||||||
const std::string & token,
|
const std::string &token, const std::string &username, const std::string &pub_key);
|
||||||
const std::string & username,
|
|
||||||
const std::string & pub_key);
|
|
||||||
|
|
||||||
std::string gen_token(
|
std::string gen_token(
|
||||||
const std::string & issuer,
|
const std::string &username,
|
||||||
const std::string & username,
|
const std::string &pub_key,
|
||||||
const std::string & pub_key,
|
const std::string &priv_key,
|
||||||
const std::string & priv_key,
|
const std::chrono::time_point<std::chrono::system_clock> &issue_time,
|
||||||
const std::chrono::time_point<std::chrono::system_clock> & issue_time,
|
const std::chrono::time_point<std::chrono::system_clock> &expr_time);
|
||||||
const std::chrono::time_point<std::chrono::system_clock> & expr_time);
|
|
||||||
|
|
|
||||||
|
|
@ -16,25 +16,25 @@
|
||||||
|
|
||||||
AuthList::AuthList() : _map{} {}
|
AuthList::AuthList() : _map{} {}
|
||||||
|
|
||||||
void AuthList::add(const std::string & username, const time_T& expr_time)
|
void AuthList::add(const std::string &username, const time_T &expr_time)
|
||||||
{
|
{
|
||||||
// Add the user to the list or update it's expr time if
|
// Add the user to the list or update it's expr time if
|
||||||
// it's already there.
|
// it's already there.
|
||||||
_map[username] = expr_time;
|
_map[username] = expr_time;
|
||||||
}
|
}
|
||||||
|
|
||||||
void AuthList::remove(const std::string & username)
|
void AuthList::remove(const std::string &username)
|
||||||
{
|
{
|
||||||
// Remove the user
|
// Remove the user
|
||||||
_map.erase(username);
|
_map.erase(username);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool AuthList::confirm(const std::string & username)
|
bool AuthList::confirm(const std::string &username)
|
||||||
{
|
{
|
||||||
// Is the user in the map?
|
// Is the user in the map?
|
||||||
const auto iter = _map.find(username);
|
const auto iter = _map.find(username);
|
||||||
|
|
||||||
if(iter == _map.end())
|
if (iter == _map.end())
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
@ -42,7 +42,7 @@ bool AuthList::confirm(const std::string & username)
|
||||||
// Has the token expired?
|
// Has the token expired?
|
||||||
const auto now = std::chrono::system_clock::now();
|
const auto now = std::chrono::system_clock::now();
|
||||||
const auto expr_time = std::get<1>(*iter);
|
const auto expr_time = std::get<1>(*iter);
|
||||||
if(now < expr_time)
|
if (now < expr_time)
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -13,30 +13,33 @@
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
#include <j7s-plugin/utils.h>
|
#include <j7s-plugin/utils.h>
|
||||||
|
|
||||||
|
#include <filesystem>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <j7s-plugin/AuthList.hpp>
|
#include <j7s-plugin/AuthList.hpp>
|
||||||
#include <j7s-plugin/Authorizer.hpp>
|
#include <j7s-plugin/Authorizer.hpp>
|
||||||
|
|
||||||
#include <tuple>
|
#include <tuple>
|
||||||
#include <filesystem>
|
|
||||||
|
|
||||||
// Util.
|
// Util.
|
||||||
std::tuple<bool, bool> checkACL(const std::string& user, const YAML::Node& aclFile);
|
std::tuple<bool, bool> checkACL(const std::string &user, const YAML::Node &aclFile);
|
||||||
std::optional<std::string> getKey(const std::string& user, const YAML::Node& keyFile);
|
std::optional<std::string> getKey(const std::string &user, const YAML::Node &keyFile);
|
||||||
|
|
||||||
// Class implementation.
|
// Class implementation.
|
||||||
Authorizer::Authorizer(
|
Authorizer::Authorizer(const std::string &keyFilePath, const std::string &aclFilePath) :
|
||||||
const std::string & keyFilePath, const std::string & aclFilePath) :
|
|
||||||
_keyFile{keyFilePath}, _aclFile{aclFilePath}
|
_keyFile{keyFilePath}, _aclFile{aclFilePath}
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Authorizer::add(const std::string &token, const std::string &username)
|
||||||
bool Authorizer::add(const std::string & token, const std::string & username)
|
|
||||||
{
|
{
|
||||||
|
// We should protect from this already.
|
||||||
|
if (token.empty() or username.empty())
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
const auto key = getKey(username, _keyFile);
|
const auto key = getKey(username, _keyFile);
|
||||||
|
|
||||||
if(not key)
|
if (not key)
|
||||||
{
|
{
|
||||||
std::cerr << "Could not read key for user." << std::endl;
|
std::cerr << "Could not read key for user." << std::endl;
|
||||||
return false;
|
return false;
|
||||||
|
|
@ -64,41 +67,39 @@ bool Authorizer::add(const std::string & token, const std::string & username)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Authorizer::can_read(const std::string &username)
|
||||||
bool Authorizer::can_read(const std::string & username)
|
|
||||||
{
|
{
|
||||||
return _readList.confirm(username);
|
return _readList.confirm(username);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Authorizer::can_write(const std::string & username)
|
bool Authorizer::can_write(const std::string &username)
|
||||||
{
|
{
|
||||||
return _writeList.confirm(username);
|
return _writeList.confirm(username);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Authorizer::logout(const std::string & username)
|
void Authorizer::logout(const std::string &username)
|
||||||
{
|
{
|
||||||
_writeList.remove(username);
|
_writeList.remove(username);
|
||||||
_readList.remove(username);
|
_readList.remove(username);
|
||||||
_unknownList.remove(username);
|
_unknownList.remove(username);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Authorizer::add_unknown(const std::string & username)
|
void Authorizer::add_unknown(const std::string &username)
|
||||||
{
|
{
|
||||||
_unknownList.add(username, time_T::max());
|
_unknownList.add(username, time_T::max());
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Authorizer::is_unknown(const std::string & username)
|
bool Authorizer::is_unknown(const std::string &username)
|
||||||
{
|
{
|
||||||
return (username.empty() or _unknownList.confirm(username));
|
return (username.empty() or _unknownList.confirm(username));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Util.
|
// Util.
|
||||||
std::tuple<bool, bool> checkACL(const std::string& user, const YAML::Node& aclFile)
|
std::tuple<bool, bool> checkACL(const std::string &user, const YAML::Node &aclFile)
|
||||||
{
|
{
|
||||||
// TODO: Make sure default exists.
|
// TODO: Make sure default exists.
|
||||||
YAML::Node userDict;
|
YAML::Node userDict;
|
||||||
if(aclFile[user])
|
if (aclFile[user])
|
||||||
{
|
{
|
||||||
userDict = aclFile[user];
|
userDict = aclFile[user];
|
||||||
}
|
}
|
||||||
|
|
@ -109,11 +110,11 @@ std::tuple<bool, bool> checkACL(const std::string& user, const YAML::Node& aclFi
|
||||||
|
|
||||||
bool can_read = false;
|
bool can_read = false;
|
||||||
bool can_write = false;
|
bool can_write = false;
|
||||||
if(userDict["can_read"] and userDict["can_read"].as<bool>())
|
if (userDict["can_read"] and userDict["can_read"].as<bool>())
|
||||||
{
|
{
|
||||||
can_read = true;
|
can_read = true;
|
||||||
}
|
}
|
||||||
if(userDict["can_write"] and userDict["can_write"].as<bool>())
|
if (userDict["can_write"] and userDict["can_write"].as<bool>())
|
||||||
{
|
{
|
||||||
can_write = true;
|
can_write = true;
|
||||||
}
|
}
|
||||||
|
|
@ -121,11 +122,11 @@ std::tuple<bool, bool> checkACL(const std::string& user, const YAML::Node& aclFi
|
||||||
return std::make_tuple(can_read, can_write);
|
return std::make_tuple(can_read, can_write);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::optional<std::string> getKey(const std::string& user, const YAML::Node& keyFile)
|
std::optional<std::string> getKey(const std::string &user, const YAML::Node &keyFile)
|
||||||
{
|
{
|
||||||
// TODO: Make sure default exists.
|
// TODO: Make sure default exists.
|
||||||
std::filesystem::path pathToKey;
|
std::filesystem::path pathToKey;
|
||||||
if(keyFile[user])
|
if (keyFile[user])
|
||||||
{
|
{
|
||||||
pathToKey = std::filesystem::path(keyFile[user].as<std::string>());
|
pathToKey = std::filesystem::path(keyFile[user].as<std::string>());
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -18,13 +18,12 @@
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
#include <filesystem>
|
#include <filesystem>
|
||||||
|
|
||||||
int main(int argc, char * argv[])
|
int main(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
argparse::ArgumentParser program("gen-token", "0.0.0");
|
argparse::ArgumentParser program("gen-token", "0.0.0");
|
||||||
|
|
||||||
program.add_argument("--pub-key").required().help("Pub key of signer.");
|
program.add_argument("--pub-key").required().help("Pub key of signer.");
|
||||||
program.add_argument("--priv-key").required().help("Private key of signer.");
|
program.add_argument("--priv-key").required().help("Private key of signer.");
|
||||||
program.add_argument("--issuer").required().help("Issuer to assign to signed key.");
|
|
||||||
program.add_argument("--username").required().help("Username assigned to key.");
|
program.add_argument("--username").required().help("Username assigned to key.");
|
||||||
program.add_argument("--valid-days")
|
program.add_argument("--valid-days")
|
||||||
.required()
|
.required()
|
||||||
|
|
@ -41,7 +40,7 @@ int main(int argc, char * argv[])
|
||||||
{
|
{
|
||||||
program.parse_args(argc, argv);
|
program.parse_args(argc, argv);
|
||||||
}
|
}
|
||||||
catch (const std::runtime_error & err)
|
catch (const std::runtime_error &err)
|
||||||
{
|
{
|
||||||
std::cerr << err.what() << std::endl;
|
std::cerr << err.what() << std::endl;
|
||||||
std::cerr << program;
|
std::cerr << program;
|
||||||
|
|
@ -67,12 +66,7 @@ int main(int argc, char * argv[])
|
||||||
now + std::chrono::days(std::stoi(program.get<std::string>("--valid-days")));
|
now + std::chrono::days(std::stoi(program.get<std::string>("--valid-days")));
|
||||||
|
|
||||||
const auto token = gen_token(
|
const auto token = gen_token(
|
||||||
program.get<std::string>("--issuer"),
|
program.get<std::string>("--username"), pub_key.value(), priv_key.value(), now, expr_time);
|
||||||
program.get<std::string>("--username"),
|
|
||||||
pub_key.value(),
|
|
||||||
priv_key.value(),
|
|
||||||
now,
|
|
||||||
expr_time);
|
|
||||||
|
|
||||||
std::cout << token;
|
std::cout << token;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -12,20 +12,18 @@
|
||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
#include <j7s-plugin/j7s-plugin.h>
|
#include <j7s-plugin/j7s-plugin.h>
|
||||||
|
|
||||||
#include <j7s-plugin/Authorizer.hpp>
|
|
||||||
|
|
||||||
#include <j7s-plugin/utils.h>
|
#include <j7s-plugin/utils.h>
|
||||||
|
|
||||||
|
#include <filesystem>
|
||||||
|
#include <j7s-plugin/Authorizer.hpp>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <filesystem>
|
|
||||||
|
|
||||||
// Mosquitto Globals
|
// Mosquitto Globals
|
||||||
static mosquitto_plugin_id_t * plugin_id = nullptr;
|
static mosquitto_plugin_id_t *plugin_id = nullptr;
|
||||||
static std::unique_ptr<Authorizer> authorizer = nullptr;
|
static std::unique_ptr<Authorizer> authorizer = nullptr;
|
||||||
|
|
||||||
int mosquitto_plugin_version(int supported_version_count, const int * supported_versions)
|
int mosquitto_plugin_version(int supported_version_count, const int *supported_versions)
|
||||||
{
|
{
|
||||||
for (int index = 0; index < supported_version_count; index++)
|
for (int index = 0; index < supported_version_count; index++)
|
||||||
{
|
{
|
||||||
|
|
@ -38,9 +36,9 @@ int mosquitto_plugin_version(int supported_version_count, const int * supported_
|
||||||
}
|
}
|
||||||
|
|
||||||
int mosquitto_plugin_init(
|
int mosquitto_plugin_init(
|
||||||
mosquitto_plugin_id_t * identifier,
|
mosquitto_plugin_id_t *identifier,
|
||||||
void ** userdata,
|
void **userdata,
|
||||||
struct mosquitto_opt * options,
|
struct mosquitto_opt *options,
|
||||||
int option_count)
|
int option_count)
|
||||||
{
|
{
|
||||||
plugin_id = identifier;
|
plugin_id = identifier;
|
||||||
|
|
@ -93,7 +91,7 @@ int mosquitto_plugin_init(
|
||||||
return MOSQ_ERR_SUCCESS;
|
return MOSQ_ERR_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
int mosquitto_plugin_cleanup(void * userdata, struct mosquitto_opt * options, int option_count)
|
int mosquitto_plugin_cleanup(void *userdata, struct mosquitto_opt *options, int option_count)
|
||||||
{
|
{
|
||||||
if (plugin_id)
|
if (plugin_id)
|
||||||
{
|
{
|
||||||
|
|
@ -107,7 +105,7 @@ int mosquitto_plugin_cleanup(void * userdata, struct mosquitto_opt * options, in
|
||||||
return MOSQ_ERR_SUCCESS;
|
return MOSQ_ERR_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
int j7s_auth_basic_auth_callback(int event, void * event_data, void * userdata)
|
int j7s_auth_basic_auth_callback(int event, void *event_data, void *userdata)
|
||||||
{
|
{
|
||||||
if (not authorizer)
|
if (not authorizer)
|
||||||
{
|
{
|
||||||
|
|
@ -115,7 +113,7 @@ int j7s_auth_basic_auth_callback(int event, void * event_data, void * userdata)
|
||||||
return MOSQ_ERR_AUTH;
|
return MOSQ_ERR_AUTH;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct mosquitto_evt_basic_auth * auth_data =
|
struct mosquitto_evt_basic_auth *auth_data =
|
||||||
static_cast<struct mosquitto_evt_basic_auth *>(event_data);
|
static_cast<struct mosquitto_evt_basic_auth *>(event_data);
|
||||||
|
|
||||||
if (!auth_data->username)
|
if (!auth_data->username)
|
||||||
|
|
@ -142,14 +140,14 @@ int j7s_auth_basic_auth_callback(int event, void * event_data, void * userdata)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int j7s_acl_check_callback(int event, void * event_data, void * userdata)
|
int j7s_acl_check_callback(int event, void *event_data, void *userdata)
|
||||||
{
|
{
|
||||||
if (not authorizer)
|
if (not authorizer)
|
||||||
{
|
{
|
||||||
return MOSQ_ERR_ACL_DENIED;
|
return MOSQ_ERR_ACL_DENIED;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct mosquitto_evt_acl_check * acl_data =
|
struct mosquitto_evt_acl_check *acl_data =
|
||||||
static_cast<struct mosquitto_evt_acl_check *>(event_data);
|
static_cast<struct mosquitto_evt_acl_check *>(event_data);
|
||||||
|
|
||||||
const std::string username = std::string(mosquitto_client_username(acl_data->client));
|
const std::string username = std::string(mosquitto_client_username(acl_data->client));
|
||||||
|
|
@ -174,9 +172,9 @@ int j7s_acl_check_callback(int event, void * event_data, void * userdata)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int j7s_disconnect_callback(int event, void * event_data, void * userdata)
|
int j7s_disconnect_callback(int event, void *event_data, void *userdata)
|
||||||
{
|
{
|
||||||
struct mosquitto_evt_disconnect * disconnect_data =
|
struct mosquitto_evt_disconnect *disconnect_data =
|
||||||
static_cast<struct mosquitto_evt_disconnect *>(event_data);
|
static_cast<struct mosquitto_evt_disconnect *>(event_data);
|
||||||
|
|
||||||
const std::string username = std::string(mosquitto_client_username(disconnect_data->client));
|
const std::string username = std::string(mosquitto_client_username(disconnect_data->client));
|
||||||
|
|
|
||||||
|
|
@ -18,8 +18,9 @@
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
|
#include <system_error>
|
||||||
|
|
||||||
std::optional<std::string> read_key(const std::string & key_file)
|
std::optional<std::string> read_key(const std::string &key_file)
|
||||||
{
|
{
|
||||||
// Read key from file.
|
// Read key from file.
|
||||||
std::ifstream key_stream(key_file, std::ios::binary);
|
std::ifstream key_stream(key_file, std::ios::binary);
|
||||||
|
|
@ -29,26 +30,34 @@ std::optional<std::string> read_key(const std::string & key_file)
|
||||||
}
|
}
|
||||||
std::stringstream ss;
|
std::stringstream ss;
|
||||||
ss << key_stream.rdbuf();
|
ss << key_stream.rdbuf();
|
||||||
return ss.str();
|
const std::string key(ss.str());
|
||||||
|
if (key.empty())
|
||||||
|
{
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
|
||||||
|
return key;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::tuple<bool, std::chrono::time_point<std::chrono::system_clock>> validate(
|
std::tuple<bool, std::chrono::time_point<std::chrono::system_clock>> validate(
|
||||||
const std::string & token,
|
const std::string &token, const std::string &username, const std::string &pub_key)
|
||||||
const std::string & username,
|
|
||||||
const std::string & pub_key)
|
|
||||||
{
|
{
|
||||||
|
if (token.empty() or username.empty() or pub_key.empty())
|
||||||
|
{
|
||||||
|
return std::make_tuple(false, std::chrono::system_clock::now());
|
||||||
|
}
|
||||||
|
|
||||||
const auto decoded_token = jwt::decode(token);
|
const auto decoded_token = jwt::decode(token);
|
||||||
|
|
||||||
// Is the token valid?
|
|
||||||
const auto verifier =
|
|
||||||
jwt::verify().allow_algorithm(jwt::algorithm::rs256(pub_key));
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
// Is the token valid?
|
||||||
|
const auto verifier = jwt::verify().allow_algorithm(jwt::algorithm::rs256(pub_key));
|
||||||
verifier.verify(decoded_token);
|
verifier.verify(decoded_token);
|
||||||
}
|
}
|
||||||
catch (jwt::error::token_verification_exception & exception)
|
catch (std::system_error &exception)
|
||||||
{
|
{
|
||||||
std::cerr << exception.what() << std::endl;
|
std::cerr << "Token Verification Failed: " << exception.what() << std::endl;
|
||||||
return std::make_tuple(false, std::chrono::system_clock::now());
|
return std::make_tuple(false, std::chrono::system_clock::now());
|
||||||
}
|
}
|
||||||
auto claims = decoded_token.get_payload_claims();
|
auto claims = decoded_token.get_payload_claims();
|
||||||
|
|
@ -71,14 +80,14 @@ std::tuple<bool, std::chrono::time_point<std::chrono::system_clock>> validate(
|
||||||
std::cerr << "Missing mqtt claim." << std::endl;
|
std::cerr << "Missing mqtt claim." << std::endl;
|
||||||
return std::make_tuple(false, std::chrono::system_clock::now());
|
return std::make_tuple(false, std::chrono::system_clock::now());
|
||||||
}
|
}
|
||||||
if(not claims["mqtt"].as_bool())
|
if (not(claims["mqtt"].as_string() == "true"))
|
||||||
{
|
{
|
||||||
std::cerr << "Not claiming can do mqtt." << std::endl;
|
std::cerr << "Not claiming can do mqtt." << std::endl;
|
||||||
return std::make_tuple(false, std::chrono::system_clock::now());
|
return std::make_tuple(false, std::chrono::system_clock::now());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Do we have an expiration time?
|
// Do we have an expiration time?
|
||||||
if(not claims.contains("exp"))
|
if (not claims.contains("exp"))
|
||||||
{
|
{
|
||||||
std::cerr << "Missing expiration time claim." << std::endl;
|
std::cerr << "Missing expiration time claim." << std::endl;
|
||||||
return std::make_tuple(false, std::chrono::system_clock::now());
|
return std::make_tuple(false, std::chrono::system_clock::now());
|
||||||
|
|
@ -88,16 +97,14 @@ std::tuple<bool, std::chrono::time_point<std::chrono::system_clock>> validate(
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string gen_token(
|
std::string gen_token(
|
||||||
const std::string & issuer,
|
const std::string &username,
|
||||||
const std::string & username,
|
const std::string &pub_key,
|
||||||
const std::string & pub_key,
|
const std::string &priv_key,
|
||||||
const std::string & priv_key,
|
const std::chrono::time_point<std::chrono::system_clock> &issue_time,
|
||||||
const std::chrono::time_point<std::chrono::system_clock> & issue_time,
|
const std::chrono::time_point<std::chrono::system_clock> &expr_time)
|
||||||
const std::chrono::time_point<std::chrono::system_clock> & expr_time)
|
|
||||||
{
|
{
|
||||||
const auto token = jwt::create()
|
const auto token = jwt::create()
|
||||||
.set_type("JWT")
|
.set_type("JWT")
|
||||||
.set_issuer(issuer)
|
|
||||||
.set_payload_claim("upn", jwt::claim(username))
|
.set_payload_claim("upn", jwt::claim(username))
|
||||||
.set_payload_claim("mqtt", jwt::claim(std::string("true")))
|
.set_payload_claim("mqtt", jwt::claim(std::string("true")))
|
||||||
.set_issued_at(issue_time)
|
.set_issued_at(issue_time)
|
||||||
|
|
|
||||||
|
|
@ -12,9 +12,13 @@
|
||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
#include <j7s-plugin/utils.h>
|
#include <j7s-plugin/utils.h>
|
||||||
|
|
||||||
|
#include <ctime>
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
#include "gtest/gtest.h"
|
#include "gtest/gtest.h"
|
||||||
|
|
||||||
constexpr std::string priv_key_a =
|
const std::string priv_key_a =
|
||||||
R"(-----BEGIN PRIVATE KEY-----
|
R"(-----BEGIN PRIVATE KEY-----
|
||||||
MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQC+ouwDpYOWDEyM
|
MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQC+ouwDpYOWDEyM
|
||||||
nJhwejOn+boDxw4ntiOR3kRzIANuJrbEPf3UJFL+SPPzzY7NU1A6XPz/NAccbvfn
|
nJhwejOn+boDxw4ntiOR3kRzIANuJrbEPf3UJFL+SPPzzY7NU1A6XPz/NAccbvfn
|
||||||
|
|
@ -42,9 +46,8 @@ mnjcxB3ZtRoyFWvfYx9wD3/rV4sMtiIoorNgtJMCgYABDGH571InLE9HMO1+Czmp
|
||||||
zyvcbTAq8GiN0G4Rok95+THfa726N6BcmkZUK1xWaleO6xNGrDsBghfmgw629Ujk
|
zyvcbTAq8GiN0G4Rok95+THfa726N6BcmkZUK1xWaleO6xNGrDsBghfmgw629Ujk
|
||||||
UJ73ERYyATbA4GHM9f3dbje8pd2SFa4xF+0Xp09qY380aJrZSWsklBZPUmYiU6+W
|
UJ73ERYyATbA4GHM9f3dbje8pd2SFa4xF+0Xp09qY380aJrZSWsklBZPUmYiU6+W
|
||||||
i2MlHfF+44rBO9igkUjQKA==
|
i2MlHfF+44rBO9igkUjQKA==
|
||||||
-----END PRIVATE KEY-----)"
|
-----END PRIVATE KEY-----)";
|
||||||
|
const std::string pub_key_a =
|
||||||
constexpr std::string pub_key_a =
|
|
||||||
R"(-----BEGIN PUBLIC KEY-----
|
R"(-----BEGIN PUBLIC KEY-----
|
||||||
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvqLsA6WDlgxMjJyYcHoz
|
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvqLsA6WDlgxMjJyYcHoz
|
||||||
p/m6A8cOJ7Yjkd5EcyADbia2xD391CRS/kjz882OzVNQOlz8/zQHHG7353O/HY9d
|
p/m6A8cOJ7Yjkd5EcyADbia2xD391CRS/kjz882OzVNQOlz8/zQHHG7353O/HY9d
|
||||||
|
|
@ -54,7 +57,8 @@ m0MrwLnIGkwyp1O9r4jTsaoPL+WxhflrU4ysHs5mLckPGe3aRkGzC9bZExEME6uZ
|
||||||
9Hfn9zmE+Y53zD0qSiYmDZS6sQiTxozXEkcY880bf3EWM4QD364jv35GBrUHCzQe
|
9Hfn9zmE+Y53zD0qSiYmDZS6sQiTxozXEkcY880bf3EWM4QD364jv35GBrUHCzQe
|
||||||
XQIDAQAB
|
XQIDAQAB
|
||||||
-----END PUBLIC KEY-----)";
|
-----END PUBLIC KEY-----)";
|
||||||
constexpr std::string priv_key_b =
|
|
||||||
|
const std::string priv_key_b =
|
||||||
R"(-----BEGIN PRIVATE KEY-----
|
R"(-----BEGIN PRIVATE KEY-----
|
||||||
MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQCYq8QNOXZRoAid
|
MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQCYq8QNOXZRoAid
|
||||||
R7cKE9byr+9WekPMNDNkaKTjRUoXj8lUgno3y5tIDEIqhcv4thTLAxzQD4N+bVA3
|
R7cKE9byr+9WekPMNDNkaKTjRUoXj8lUgno3y5tIDEIqhcv4thTLAxzQD4N+bVA3
|
||||||
|
|
@ -83,7 +87,7 @@ t4/SVFXBRLzse8AB3V6qSEwgCaUfeuj0Qq93nrkTIodHFWXuFoQTgQrA29VWbK6x
|
||||||
PSwjdVNwYES+Hg+LbXP8Fo+u5sGhcWLzWdmFp3UdUm5Mv76Oo+MriZNnS4RQiX0+
|
PSwjdVNwYES+Hg+LbXP8Fo+u5sGhcWLzWdmFp3UdUm5Mv76Oo+MriZNnS4RQiX0+
|
||||||
Y8PiIt3YYCsowmchtEggaQ==
|
Y8PiIt3YYCsowmchtEggaQ==
|
||||||
-----END PRIVATE KEY-----)";
|
-----END PRIVATE KEY-----)";
|
||||||
constexpr std::string pub_key_b =
|
const std::string pub_key_b =
|
||||||
R"(-----BEGIN PUBLIC KEY-----
|
R"(-----BEGIN PUBLIC KEY-----
|
||||||
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAmKvEDTl2UaAInUe3ChPW
|
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAmKvEDTl2UaAInUe3ChPW
|
||||||
8q/vVnpDzDQzZGik40VKF4/JVIJ6N8ubSAxCKoXL+LYUywMc0A+Dfm1QN1xdWTH5
|
8q/vVnpDzDQzZGik40VKF4/JVIJ6N8ubSAxCKoXL+LYUywMc0A+Dfm1QN1xdWTH5
|
||||||
|
|
@ -94,11 +98,60 @@ wmwOQRQS2h5xR1Z/o6HBIGnzllI67mHMK1HGbgq/DsvCi6s+sOV7Wvwe8dC8sd87
|
||||||
xwIDAQAB
|
xwIDAQAB
|
||||||
-----END PUBLIC KEY-----)";
|
-----END PUBLIC KEY-----)";
|
||||||
|
|
||||||
|
using time_T = std::chrono::time_point<std::chrono::system_clock>;
|
||||||
|
|
||||||
// Demonstrate some basic assertions.
|
TEST(TokenTest, SimpleTwoWay)
|
||||||
TEST(TokenTest, TwoWay) {
|
{
|
||||||
constexpr std::string issuer = "james-keycloak";
|
const std::string username = "james";
|
||||||
constexpr std::string username = "james";
|
const time_T now = std::chrono::system_clock::now();
|
||||||
constexpr
|
const time_T expire = now + std::chrono::seconds(1);
|
||||||
const auto token = gen_token(
|
|
||||||
|
const auto token = gen_token(username, pub_key_a, priv_key_a, now, expire);
|
||||||
|
|
||||||
|
auto [valid, end] = validate(token, username, pub_key_a);
|
||||||
|
|
||||||
|
std::time_t expire_time = std::chrono::system_clock::to_time_t(expire);
|
||||||
|
std::time_t end_time = std::chrono::system_clock::to_time_t(end);
|
||||||
|
|
||||||
|
EXPECT_TRUE(valid);
|
||||||
|
EXPECT_EQ(end_time, expire_time);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(TokenTest, InvalidUsername)
|
||||||
|
{
|
||||||
|
const std::string username = "james";
|
||||||
|
const time_T now = std::chrono::system_clock::now();
|
||||||
|
const time_T expire = now + std::chrono::seconds(1);
|
||||||
|
const auto token = gen_token(username, pub_key_a, priv_key_a, now, expire);
|
||||||
|
|
||||||
|
const std::string notjames = "not_james";
|
||||||
|
const auto [valid, end] = validate(token, notjames, pub_key_a);
|
||||||
|
|
||||||
|
EXPECT_FALSE(valid);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(TokenTest, WrongKey)
|
||||||
|
{
|
||||||
|
const std::string username = "james";
|
||||||
|
const time_T now = std::chrono::system_clock::now();
|
||||||
|
const time_T expire = now + std::chrono::seconds(1);
|
||||||
|
const auto token = gen_token(username, pub_key_a, priv_key_a, now, expire);
|
||||||
|
|
||||||
|
const auto [valid, end] = validate(token, username, pub_key_b);
|
||||||
|
|
||||||
|
EXPECT_FALSE(valid);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(TokenTest, NonsenseKey)
|
||||||
|
{
|
||||||
|
const std::string username = "james";
|
||||||
|
const time_T now = std::chrono::system_clock::now();
|
||||||
|
const time_T expire = now + std::chrono::seconds(1);
|
||||||
|
const auto token = gen_token(username, pub_key_a, priv_key_a, now, expire);
|
||||||
|
|
||||||
|
const std::string nonsenseKey = "lslslslsl";
|
||||||
|
|
||||||
|
const auto [valid, end] = validate(token, username, nonsenseKey);
|
||||||
|
|
||||||
|
EXPECT_FALSE(valid);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue