diff --git a/CMakeLists.txt b/CMakeLists.txt index a555332..3b3f6c7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -61,7 +61,7 @@ include_directories(/usr/local/include /usr/local/opt/openssl/include src inclu configure_file(src/ow_version.h.in ${PROJECT_SOURCE_DIR}/src/ow_version.h @ONLY) add_compile_options(-Wall -Wextra) -add_definitions(-DPOCO_LOG_DEBUG="1") +add_definitions(-DPOCO_LOG_DEBUG="1" -DBOOST_NO_CXX98_FUNCTION_BASE=1) if(ASAN) add_compile_options(-fsanitize=address) diff --git a/build b/build index bf0d87a..9d60796 100644 --- a/build +++ b/build @@ -1 +1 @@ -4 \ No newline at end of file +11 \ No newline at end of file diff --git a/src/framework/ConfigurationValidator.cpp b/src/framework/ConfigurationValidator.cpp index f1bb9ef..28b6e0c 100644 --- a/src/framework/ConfigurationValidator.cpp +++ b/src/framework/ConfigurationValidator.cpp @@ -34,6 +34,10 @@ static std::string DefaultUCentralSchema = R"foo( "$schema": "http://json-schema.org/draft-07/schema#", "type": "object", "properties": { + "strict": { + "type": "boolean", + "default": false + }, "uuid": { "type": "integer" }, @@ -114,6 +118,20 @@ static std::string DefaultUCentralSchema = R"foo( "random-password": { "type": "boolean", "default": false + }, + "beacon-advertisement": { + "type": "object", + "properties": { + "device-name": { + "type": "boolean" + }, + "device-serial": { + "type": "boolean" + }, + "network-id": { + "type": "integer" + } + } } } }, @@ -222,6 +240,52 @@ static std::string DefaultUCentralSchema = R"foo( } } }, + "interface.ssid.encryption": { + "type": "object", + "properties": { + "proto": { + "type": "string", + "enum": [ + "none", + "owe", + "owe-transition", + "psk", + "psk2", + "psk-mixed", + "psk2-radius", + "wpa", + "wpa2", + "wpa-mixed", + "sae", + "sae-mixed", + "wpa3", + "wpa3-192", + "wpa3-mixed" + ], + "examples": [ + "psk2" + ] + }, + "key": { + "type": "string", + "maxLength": 63, + "minLength": 8 + }, + "ieee80211w": { + "type": "string", + "enum": [ + "disabled", + "optional", + "required" + ], + "default": "disabled" + }, + "key-caching": { + "type": "boolean", + "default": true + } + } + }, "definitions": { "type": "object", "properties": { @@ -716,7 +780,8 @@ static std::string DefaultUCentralSchema = R"foo( "type": "string", "enum": [ "dynamic", - "static" + "static", + "none" ], "examples": [ "static" @@ -1006,52 +1071,6 @@ static std::string DefaultUCentralSchema = R"foo( } ] }, - "interface.ssid.encryption": { - "type": "object", - "properties": { - "proto": { - "type": "string", - "enum": [ - "none", - "owe", - "owe-transition", - "psk", - "psk2", - "psk-mixed", - "psk2-radius", - "wpa", - "wpa2", - "wpa-mixed", - "sae", - "sae-mixed", - "wpa3", - "wpa3-192", - "wpa3-mixed" - ], - "examples": [ - "psk2" - ] - }, - "key": { - "type": "string", - "maxLength": 63, - "minLength": 8 - }, - "ieee80211w": { - "type": "string", - "enum": [ - "disabled", - "optional", - "required" - ], - "default": "disabled" - }, - "key-caching": { - "type": "boolean", - "default": true - } - } - }, "interface.ssid.multi-psk": { "type": "object", "properties": { @@ -2020,6 +2039,11 @@ static std::string DefaultUCentralSchema = R"foo( "decription": "This option allows embedding custom vendor specific IEs inside the beacons of a BSS in AP mode.", "type": "string" }, + "tip-information-element": { + "decription": "The device will broadcast the TIP vendor IE inside its beacons if this option is enabled.", + "type": "boolean", + "default": true + }, "fils-discovery-interval": { "type": "integer", "default": 20, @@ -2443,6 +2467,24 @@ static std::string DefaultUCentralSchema = R"foo( "type": "boolean", "default": false }, + "mode": { + "type": "string", + "enum": [ + "radius", + "user" + ] + }, + "port-filter": { + "type": "array", + "items": { + "type": "string", + "examples": [ + { + "LAN1": null + } + ] + } + }, "server-certificate": { "type": "string" }, @@ -2454,6 +2496,77 @@ static std::string DefaultUCentralSchema = R"foo( "items": { "$ref": "#/$defs/interface.ssid.radius.local-user" } + }, + "radius": { + "type": "object", + "properties": { + "nas-identifier": { + "type": "string" + }, + "auth-server-addr": { + "type": "string", + "format": "uc-host", + "examples": [ + "192.168.1.10" + ] + }, + "auth-server-port": { + "type": "integer", + "maximum": 65535, + "minimum": 1024, + "examples": [ + 1812 + ] + }, + "auth-server-secret": { + "type": "string", + "examples": [ + "secret" + ] + }, + "acct-server-addr": { + "type": "string", + "format": "uc-host", + "examples": [ + "192.168.1.10" + ] + }, + "acct-server-port": { + "type": "integer", + "maximum": 65535, + "minimum": 1024, + "examples": [ + 1813 + ] + }, + "acct-server-secret": { + "type": "string", + "examples": [ + "secret" + ] + }, + "coa-server-addr": { + "type": "string", + "format": "uc-host", + "examples": [ + "192.168.1.10" + ] + }, + "coa-server-port": { + "type": "integer", + "maximum": 65535, + "minimum": 1024, + "examples": [ + 1814 + ] + }, + "coa-server-secret": { + "type": "string", + "examples": [ + "secret" + ] + } + } } } }, @@ -2777,6 +2890,12 @@ static std::string DefaultUCentralSchema = R"foo( } } }, + "services": { + "type": "array", + "items": { + "type": "string" + } + }, "classifier": { "type": "array", "items": { @@ -3019,6 +3138,24 @@ static std::string DefaultUCentralSchema = R"foo( "relay-server": { "type": "string", "format": "uc-ip" + }, + "circuit-id-format": { + "type": "string", + "enum": [ + "vlan-id", + "ap-mac", + "ssid" + ], + "default": "vlan-id" + }, + "remote-id-format": { + "type": "string", + "enum": [ + "vlan-id", + "ap-mac", + "ssid" + ], + "default": "ap-mac" } } } diff --git a/src/framework/EventBusManager.cpp b/src/framework/EventBusManager.cpp index 28d8037..ca28ad9 100644 --- a/src/framework/EventBusManager.cpp +++ b/src/framework/EventBusManager.cpp @@ -14,18 +14,18 @@ namespace OpenWifi { void EventBusManager::run() { Running_ = true; Utils::SetThreadName("fmwk:EventMgr"); - auto Msg = std::make_shared(MicroServiceMakeSystemEventMessage(KafkaTopics::ServiceEvents::EVENT_JOIN)); + auto Msg = (MicroServiceMakeSystemEventMessage(KafkaTopics::ServiceEvents::EVENT_JOIN)); KafkaManager()->PostMessage(KafkaTopics::SERVICE_EVENTS, MicroServicePrivateEndPoint(), Msg, false); while (Running_) { Poco::Thread::trySleep((unsigned long)MicroServiceDaemonBusTimer()); if (!Running_) break; - Msg = std::make_shared(MicroServiceMakeSystemEventMessage(KafkaTopics::ServiceEvents::EVENT_KEEP_ALIVE)); + Msg = (MicroServiceMakeSystemEventMessage(KafkaTopics::ServiceEvents::EVENT_KEEP_ALIVE)); KafkaManager()->PostMessage(KafkaTopics::SERVICE_EVENTS, MicroServicePrivateEndPoint(), Msg, false); } - Msg = std::make_shared(MicroServiceMakeSystemEventMessage(KafkaTopics::ServiceEvents::EVENT_LEAVE)); + Msg = (MicroServiceMakeSystemEventMessage(KafkaTopics::ServiceEvents::EVENT_LEAVE)); KafkaManager()->PostMessage(KafkaTopics::SERVICE_EVENTS, MicroServicePrivateEndPoint(), Msg, false); }; diff --git a/src/framework/KafkaManager.cpp b/src/framework/KafkaManager.cpp index 09527a5..9381065 100644 --- a/src/framework/KafkaManager.cpp +++ b/src/framework/KafkaManager.cpp @@ -6,6 +6,7 @@ #include "fmt/format.h" #include "framework/MicroServiceFuncs.h" +#include "cppkafka/utils/consumer_dispatcher.h" namespace OpenWifi { @@ -99,9 +100,12 @@ namespace OpenWifi { try { auto Msg = dynamic_cast(Note.get()); if (Msg != nullptr) { - Producer.produce(cppkafka::MessageBuilder(Msg->Topic()) - .key(Msg->Key()) - .payload(Msg->Payload())); + auto NewMessage = cppkafka::MessageBuilder(Msg->Topic()); + NewMessage.key(Msg->Key()); + NewMessage.partition(0); + NewMessage.payload(Msg->Payload()); + Producer.produce(NewMessage); + Producer.flush(); } } catch (const cppkafka::HandleException &E) { poco_warning(Logger_, @@ -156,43 +160,49 @@ namespace OpenWifi { } }); - bool AutoCommit = MicroServiceConfigGetBool("openwifi.kafka.auto.commit", false); - auto BatchSize = MicroServiceConfigGetInt("openwifi.kafka.consumer.batchsize", 20); + // bool AutoCommit = MicroServiceConfigGetBool("openwifi.kafka.auto.commit", false); + // auto BatchSize = MicroServiceConfigGetInt("openwifi.kafka.consumer.batchsize", 100); Types::StringVec Topics; - KafkaManager()->Topics(Topics); + std::for_each(Topics_.begin(),Topics_.end(), + [&](const std::string & T) { Topics.emplace_back(T); }); Consumer.subscribe(Topics); Running_ = true; - while (Running_) { - try { - std::vector MsgVec = - Consumer.poll_batch(BatchSize, std::chrono::milliseconds(100)); - for (auto const &Msg : MsgVec) { - if (!Msg) - continue; - if (Msg.get_error()) { - if (!Msg.is_eof()) { - poco_error(Logger_, - fmt::format("Error: {}", Msg.get_error().to_string())); + std::vector MsgVec; + + Dispatcher_ = std::make_unique(Consumer); + + Dispatcher_->run( + // Callback executed whenever a new message is consumed + [&](cppkafka::Message msg) { + // Print the key (if any) + std::lock_guard G(ConsumerMutex_); + auto It = Notifiers_.find(msg.get_topic()); + if (It != Notifiers_.end()) { + const auto &FL = It->second; + for (const auto &[CallbackFunc, _] : FL) { + try { + CallbackFunc(msg.get_key(), msg.get_payload()); + } catch(const Poco::Exception &E) { + + } catch(...) { + } - if (!AutoCommit) - Consumer.async_commit(Msg); - continue; } - KafkaManager()->Dispatch(Msg.get_topic().c_str(), Msg.get_key(), std::make_shared(Msg.get_payload())); - if (!AutoCommit) - Consumer.async_commit(Msg); } - } catch (const cppkafka::HandleException &E) { - poco_warning(Logger_, - fmt::format("Caught a Kafka exception (consumer): {}", E.what())); - } catch (const Poco::Exception &E) { - Logger_.log(E); - } catch (...) { - poco_error(Logger_, "std::exception"); + Consumer.commit(msg); + }, + // Whenever there's an error (other than the EOF soft error) + [&Logger_](cppkafka::Error error) { + poco_warning(Logger_,fmt::format("Error: {}", error.to_string())); + }, + // Whenever EOF is reached on a partition, print this + [&Logger_](cppkafka::ConsumerDispatcher::EndOfFile, const cppkafka::TopicPartition& topic_partition) { + poco_debug(Logger_,fmt::format("Partition {} EOF", topic_partition.get_partition())); } - } + ); + Consumer.unsubscribe(); poco_information(Logger_, "Stopped..."); } @@ -213,14 +223,13 @@ namespace OpenWifi { } void KafkaProducer::Produce(const char *Topic, const std::string &Key, - std::shared_ptr Payload) { + const std::string &Payload) { std::lock_guard G(Mutex_); Queue_.enqueueNotification(new KafkaMessage(Topic, Key, Payload)); } void KafkaConsumer::Start() { if (!Running_) { - Running_ = true; Worker_.start(*this); } } @@ -228,29 +237,16 @@ namespace OpenWifi { void KafkaConsumer::Stop() { if (Running_) { Running_ = false; - Worker_.wakeUp(); - Worker_.join(); - } - } - - void KafkaDispatcher::Start() { - if (!Running_) { - Running_ = true; - Worker_.start(*this); - } - } - - void KafkaDispatcher::Stop() { - if (Running_) { - Running_ = false; - Queue_.wakeUpAll(); + if(Dispatcher_) { + Dispatcher_->stop(); + } Worker_.join(); } } - auto KafkaDispatcher::RegisterTopicWatcher(const std::string &Topic, + std::uint64_t KafkaConsumer::RegisterTopicWatcher(const std::string &Topic, Types::TopicNotifyFunction &F) { - std::lock_guard G(Mutex_); + std::lock_guard G(ConsumerMutex_); auto It = Notifiers_.find(Topic); if (It == Notifiers_.end()) { Types::TopicNotifyFunctionList L; @@ -259,11 +255,12 @@ namespace OpenWifi { } else { It->second.emplace(It->second.end(), std::make_pair(F, FunctionId_)); } + Topics_.insert(Topic); return FunctionId_++; } - void KafkaDispatcher::UnregisterTopicWatcher(const std::string &Topic, int Id) { - std::lock_guard G(Mutex_); + void KafkaConsumer::UnregisterTopicWatcher(const std::string &Topic, int Id) { + std::lock_guard G(ConsumerMutex_); auto It = Notifiers_.find(Topic); if (It != Notifiers_.end()) { Types::TopicNotifyFunctionList &L = It->second; @@ -275,56 +272,17 @@ namespace OpenWifi { } } - void KafkaDispatcher::Dispatch(const char *Topic, const std::string &Key, - const std::shared_ptr Payload) { - std::lock_guard G(Mutex_); - auto It = Notifiers_.find(Topic); - if (It != Notifiers_.end()) { - Queue_.enqueueNotification(new KafkaMessage(Topic, Key, Payload)); - } - } - - void KafkaDispatcher::run() { - Poco::Logger &Logger_ = - Poco::Logger::create("KAFKA-DISPATCHER", KafkaManager()->Logger().getChannel()); - poco_information(Logger_, "Starting..."); - Poco::AutoPtr Note(Queue_.waitDequeueNotification()); - Utils::SetThreadName("kafka:dispatch"); - while (Note && Running_) { - auto Msg = dynamic_cast(Note.get()); - if (Msg != nullptr) { - auto It = Notifiers_.find(Msg->Topic()); - if (It != Notifiers_.end()) { - const auto &FL = It->second; - for (const auto &[CallbackFunc, _] : FL) { - CallbackFunc(Msg->Key(), Msg->Payload()); - } - } - } - Note = Queue_.waitDequeueNotification(); - } - poco_information(Logger_, "Stopped..."); - } - - void KafkaDispatcher::Topics(std::vector &T) { - T.clear(); - for (const auto &[TopicName, _] : Notifiers_) - T.push_back(TopicName); - } - int KafkaManager::Start() { if (!KafkaEnabled_) return 0; ConsumerThr_.Start(); ProducerThr_.Start(); - Dispatcher_.Start(); return 0; } void KafkaManager::Stop() { if (KafkaEnabled_) { poco_information(Logger(), "Stopping..."); - Dispatcher_.Stop(); ProducerThr_.Stop(); ConsumerThr_.Stop(); poco_information(Logger(), "Stopped..."); @@ -333,39 +291,28 @@ namespace OpenWifi { } void KafkaManager::PostMessage(const char *topic, const std::string &key, - const std::shared_ptr PayLoad, bool WrapMessage) { + const std::string & PayLoad, bool WrapMessage) { if (KafkaEnabled_) { ProducerThr_.Produce(topic, key, WrapMessage ? WrapSystemId(PayLoad) : PayLoad); } } - void KafkaManager::Dispatch(const char *Topic, const std::string &Key, - const std::shared_ptr Payload) { - Dispatcher_.Dispatch(Topic, Key, Payload); - } - - [[nodiscard]] const std::shared_ptr KafkaManager::WrapSystemId(const std::shared_ptr PayLoad) { - *PayLoad = SystemInfoWrapper_ + *PayLoad + "}"; - return PayLoad; - } - - uint64_t KafkaManager::RegisterTopicWatcher(const std::string &Topic, - Types::TopicNotifyFunction &F) { + void KafkaManager::PostMessage(const char *topic, const std::string &key, + const Poco::JSON::Object &Object, bool WrapMessage) { if (KafkaEnabled_) { - return Dispatcher_.RegisterTopicWatcher(Topic, F); - } else { - return 0; + std::ostringstream ObjectStr; + Object.stringify(ObjectStr); + ProducerThr_.Produce(topic, key, WrapMessage ? WrapSystemId(ObjectStr.str()) : ObjectStr.str()); } } - void KafkaManager::UnregisterTopicWatcher(const std::string &Topic, uint64_t Id) { - if (KafkaEnabled_) { - Dispatcher_.UnregisterTopicWatcher(Topic, Id); - } + [[nodiscard]] std::string KafkaManager::WrapSystemId(const std::string & PayLoad) { + return fmt::format( R"lit({{ "system" : {{ "id" : {}, + "host" : "{}" }}, + "payload" : {} }})lit", MicroServiceID(), + MicroServicePrivateEndPoint(), PayLoad ) ; } - void KafkaManager::Topics(std::vector &T) { Dispatcher_.Topics(T); } - void KafkaManager::PartitionAssignment(const cppkafka::TopicPartitionList &partitions) { poco_information( Logger(), fmt::format("Partition assigned: {}...", partitions.front().get_partition())); diff --git a/src/framework/KafkaManager.h b/src/framework/KafkaManager.h index 3ef5940..e6272d3 100644 --- a/src/framework/KafkaManager.h +++ b/src/framework/KafkaManager.h @@ -6,7 +6,7 @@ #include "Poco/Notification.h" #include "Poco/NotificationQueue.h" - +#include "Poco/JSON/Object.h" #include "framework/KafkaTopics.h" #include "framework/OpenWifiTypes.h" #include "framework/SubSystemServer.h" @@ -18,17 +18,17 @@ namespace OpenWifi { class KafkaMessage : public Poco::Notification { public: - KafkaMessage(const char * Topic, const std::string &Key, std::shared_ptr Payload) + KafkaMessage(const char * Topic, const std::string &Key, const std::string &Payload) : Topic_(Topic), Key_(Key), Payload_(Payload) {} inline const char * Topic() { return Topic_; } inline const std::string &Key() { return Key_; } - inline const std::string &Payload() { return *Payload_; } + inline const std::string &Payload() { return Payload_; } private: const char *Topic_; std::string Key_; - std::shared_ptr Payload_; + std::string Payload_; }; class KafkaProducer : public Poco::Runnable { @@ -36,10 +36,10 @@ namespace OpenWifi { void run() override; void Start(); void Stop(); - void Produce(const char *Topic, const std::string &Key, std::shared_ptr Payload); + void Produce(const char *Topic, const std::string &Key, const std::string & Payload); private: - std::recursive_mutex Mutex_; + std::mutex Mutex_; Poco::Thread Worker_; mutable std::atomic_bool Running_ = false; Poco::NotificationQueue Queue_; @@ -47,33 +47,22 @@ namespace OpenWifi { class KafkaConsumer : public Poco::Runnable { public: - void run() override; void Start(); void Stop(); private: - std::recursive_mutex Mutex_; - Poco::Thread Worker_; + std::mutex ConsumerMutex_; + Types::NotifyTable Notifiers_; + Poco::Thread Worker_; mutable std::atomic_bool Running_ = false; - }; + uint64_t FunctionId_ = 1; + std::unique_ptr Dispatcher_; + std::set Topics_; - class KafkaDispatcher : public Poco::Runnable { - public: - void Start(); - void Stop(); - auto RegisterTopicWatcher(const std::string &Topic, Types::TopicNotifyFunction &F); - void UnregisterTopicWatcher(const std::string &Topic, int Id); - void Dispatch(const char *Topic, const std::string &Key, const std::shared_ptr Payload); void run() override; - void Topics(std::vector &T); - - private: - std::recursive_mutex Mutex_; - Types::NotifyTable Notifiers_; - Poco::Thread Worker_; - mutable std::atomic_bool Running_ = false; - uint64_t FunctionId_ = 1; - Poco::NotificationQueue Queue_; + friend class KafkaManager; + std::uint64_t RegisterTopicWatcher(const std::string &Topic, Types::TopicNotifyFunction &F); + void UnregisterTopicWatcher(const std::string &Topic, int Id); }; class KafkaManager : public SubSystemServer { @@ -92,20 +81,24 @@ namespace OpenWifi { void Stop() override; void PostMessage(const char *topic, const std::string &key, - std::shared_ptr PayLoad, bool WrapMessage = true); - void Dispatch(const char *Topic, const std::string &Key, std::shared_ptr Payload); - [[nodiscard]] const std::shared_ptr WrapSystemId(std::shared_ptr PayLoad); + const std::string &PayLoad, bool WrapMessage = true); + void PostMessage(const char *topic, const std::string &key, + const Poco::JSON::Object &Object, bool WrapMessage = true); + + [[nodiscard]] std::string WrapSystemId(const std::string & PayLoad); [[nodiscard]] inline bool Enabled() const { return KafkaEnabled_; } - uint64_t RegisterTopicWatcher(const std::string &Topic, Types::TopicNotifyFunction &F); - void UnregisterTopicWatcher(const std::string &Topic, uint64_t Id); - void Topics(std::vector &T); + inline std::uint64_t RegisterTopicWatcher(const std::string &Topic, Types::TopicNotifyFunction &F) { + return ConsumerThr_.RegisterTopicWatcher(Topic,F); + } + inline void UnregisterTopicWatcher(const std::string &Topic, uint64_t Id) { + return ConsumerThr_.UnregisterTopicWatcher(Topic,Id); + } private: bool KafkaEnabled_ = false; std::string SystemInfoWrapper_; KafkaProducer ProducerThr_; KafkaConsumer ConsumerThr_; - KafkaDispatcher Dispatcher_; void PartitionAssignment(const cppkafka::TopicPartitionList &partitions); void PartitionRevocation(const cppkafka::TopicPartitionList &partitions); diff --git a/src/framework/RESTAPI_Handler.h b/src/framework/RESTAPI_Handler.h index a7ed681..d6f31be 100644 --- a/src/framework/RESTAPI_Handler.h +++ b/src/framework/RESTAPI_Handler.h @@ -574,7 +574,37 @@ namespace OpenWifi { Poco::JSON::Stringifier::stringify(Object, Answer); } - inline void ReturnRawJSON(const std::string &json_doc) { + inline void ReturnObject(const std::vector &Strings) { + Poco::JSON::Array Arr; + for(const auto &String:Strings) { + Arr.add(String); + } + std::ostringstream os; + Arr.stringify(os); + return ReturnRawJSON(os.str()); + } + + template void ReturnObject(const std::vector &Objects) { + Poco::JSON::Array Arr; + for(const auto &Object:Objects) { + Poco::JSON::Object O; + Object.to_json(O); + Arr.add(O); + } + std::ostringstream os; + Arr.stringify(os); + return ReturnRawJSON(os.str()); + } + + template void ReturnObject(const T &Object) { + Poco::JSON::Object O; + Object.to_json(O); + std::ostringstream os; + O.stringify(os); + return ReturnRawJSON(os.str()); + } + + inline void ReturnRawJSON(const std::string &json_doc) { PrepareResponse(); if (Request != nullptr) { // can we compress ??? diff --git a/src/framework/SubSystemServer.cpp b/src/framework/SubSystemServer.cpp index f6df356..9dda8a3 100644 --- a/src/framework/SubSystemServer.cpp +++ b/src/framework/SubSystemServer.cpp @@ -37,6 +37,7 @@ namespace OpenWifi { P.cipherList = "ALL:!ADH:!LOW:!EXP:!MD5:@STRENGTH"; P.dhUse2048Bits = true; P.caLocation = cas_; + // P.securityLevel = auto Context = Poco::AutoPtr( new Poco::Net::Context(Poco::Net::Context::TLS_SERVER_USE, P)); @@ -53,7 +54,6 @@ namespace OpenWifi { Context->useCertificate(Cert); Context->addChainCertificate(Root); - Context->addCertificateAuthority(Root); if (level_ == Poco::Net::Context::VERIFY_STRICT) { @@ -76,18 +76,18 @@ namespace OpenWifi { L.fatal(fmt::format("Wrong Certificate({}) for Key({})", cert_file_, key_file_)); } - SSL_CTX_set_verify(SSLCtx, SSL_VERIFY_PEER, nullptr); + SSL_CTX_set_verify(SSLCtx, level_==Poco::Net::Context::VERIFY_NONE ? SSL_VERIFY_NONE : SSL_VERIFY_PEER, nullptr); if (level_ == Poco::Net::Context::VERIFY_STRICT) { SSL_CTX_set_client_CA_list(SSLCtx, SSL_load_client_CA_file(client_cas_.c_str())); + SSL_CTX_enable_ct(SSLCtx, SSL_CT_VALIDATION_STRICT); } - SSL_CTX_enable_ct(SSLCtx, SSL_CT_VALIDATION_STRICT); SSL_CTX_dane_enable(SSLCtx); Context->enableSessionCache(); Context->setSessionCacheSize(0); Context->setSessionTimeout(60); - Context->enableExtendedCertificateVerification(true); + Context->enableExtendedCertificateVerification( level_!= Poco::Net::Context::VERIFY_NONE ); Context->disableStatelessSessionResumption(); } diff --git a/src/framework/ow_constants.h b/src/framework/ow_constants.h index c1a1bf7..370ab40 100644 --- a/src/framework/ow_constants.h +++ b/src/framework/ow_constants.h @@ -40,6 +40,7 @@ namespace OpenWifi { }; } +#define DBGLINE std::cout << __LINE__ << ":" << __FILE__ << ", " << __func__ << std::endl; namespace OpenWifi::RESTAPI::Errors { struct msg { uint64_t err_num; @@ -405,7 +406,18 @@ namespace OpenWifi::RESTAPI::Errors { 1172, "The venue name already exists." }; - static const struct msg DefFirmwareNameExists { 1172, "Firmware name already exists." }; + static const struct msg InvalidGlobalReachAccount { + 1173, "Invalid Global Reach account information." + }; + static const struct msg CannotCreateCSR { + 1174, "Cannot create a CSR certificate." + }; + + static const struct msg DefFirmwareNameExists { 1175, "Firmware name already exists." }; + + static const struct msg NotAValidECKey { 1176, "Not a valid Signing Key." }; + + static const struct msg NotAValidRadiusPoolType { 1177, "Not a valid RADIUS pool type." }; static const struct msg SimulationDoesNotExist { 7000, "Simulation Instance ID does not exist." diff --git a/src/framework/utils.cpp b/src/framework/utils.cpp index a0f4c11..6c34cdb 100644 --- a/src/framework/utils.cpp +++ b/src/framework/utils.cpp @@ -3,10 +3,17 @@ // #include "Poco/Path.h" - +#include "Poco/TemporaryFile.h" +#include "Poco/Crypto/ECKey.h" #include "framework/AppServiceRegistry.h" #include "framework/utils.h" +#include +#include +#include +#include +#include + namespace OpenWifi::Utils { bool NormalizeMac(std::string &Mac) { @@ -608,4 +615,251 @@ namespace OpenWifi::Utils { return DT.timestamp().epochTime(); } + static std::string FileToString(const std::string &Filename) { + std::ifstream ifs(Filename.c_str(),std::ios_base::in|std::ios_base::binary); + std::ostringstream os; + Poco::StreamCopier::copyStream(ifs,os); + return os.str(); + } + + bool CreateX509CSR(const CSRCreationParameters & Parameters, CSRCreationResults & Results) { + int ret = 0; + RSA *r = nullptr; + BIGNUM *bne = nullptr; + + int nVersion = 0; + unsigned long e = RSA_F4; + + X509_REQ *x509_req = nullptr; + X509_NAME *x509_name = nullptr; + EVP_PKEY *pKey = nullptr; +// RSA *tem = nullptr; +// BIO *bio_err = nullptr; + + const char *szCountry = Parameters.Country.c_str(); + const char *szProvince = Parameters.Province.c_str(); + const char *szCity = Parameters.City.c_str(); + const char *szOrganization = Parameters.Organization.c_str(); + const char *szCommon = Parameters.CommonName.c_str(); + + Poco::TemporaryFile CsrPath, PubKey, PrivateKey; + std::string Result; + std::ifstream ifs; + std::ostringstream ss; + BIO *bp_public = nullptr, + *bp_private = nullptr, + *bp_csr = nullptr; + + // 1. generate rsa key + bne = BN_new(); + ret = BN_set_word(bne,e); + if(ret != 1){ + goto free_all; + } + + r = RSA_new(); + ret = RSA_generate_key_ex(r, Parameters.bits, bne, nullptr); + if(ret != 1){ + goto free_all; + } + + bp_public = BIO_new_file(PubKey.path().c_str(), "w+"); + ret = PEM_write_bio_RSAPublicKey(bp_public, r); + if(ret != 1) { + goto free_all; + } + + bp_private = BIO_new_file(PrivateKey.path().c_str(), "w+"); + ret = PEM_write_bio_RSAPrivateKey(bp_private, r, NULL, NULL, 0, NULL, NULL); + if(ret != 1) { + goto free_all; + } + +// 2. set version of x509 req + x509_req = X509_REQ_new(); + ret = X509_REQ_set_version(x509_req, nVersion); + if (ret != 1){ + goto free_all; + } + +// 3. set subject of x509 req + x509_name = X509_REQ_get_subject_name(x509_req); + + ret = X509_NAME_add_entry_by_txt(x509_name,"C", MBSTRING_ASC, (const unsigned char*)szCountry, -1, -1, 0); + if (ret != 1){ + goto free_all; + } + + ret = X509_NAME_add_entry_by_txt(x509_name,"ST", MBSTRING_ASC, (const unsigned char*)szProvince, -1, -1, 0); + if (ret != 1){ + goto free_all; + } + + ret = X509_NAME_add_entry_by_txt(x509_name,"L", MBSTRING_ASC, (const unsigned char*)szCity, -1, -1, 0); + if (ret != 1){ + goto free_all; + } + + ret = X509_NAME_add_entry_by_txt(x509_name,"O", MBSTRING_ASC, (const unsigned char*)szOrganization, -1, -1, 0); + if (ret != 1){ + goto free_all; + } + + ret = X509_NAME_add_entry_by_txt(x509_name,"CN", MBSTRING_ASC, (const unsigned char*)szCommon, -1, -1, 0); + if (ret != 1){ + goto free_all; + } + +// 4. set public key of x509 req + pKey = EVP_PKEY_new(); + EVP_PKEY_assign_RSA(pKey, r); + r = nullptr; // will be free rsa when EVP_PKEY_free(pKey) + + ret = X509_REQ_set_pubkey(x509_req, pKey); + if (ret != 1){ + goto free_all; + } + +// 5. set sign key of x509 req + ret = X509_REQ_sign(x509_req, pKey, EVP_sha1()); // return x509_req->signature->length + if (ret <= 0){ + goto free_all; + } + + bp_csr = BIO_new_file(CsrPath.path().c_str(),"w"); + ret = PEM_write_bio_X509_REQ(bp_csr, x509_req); + +// 6. free + free_all: + X509_REQ_free(x509_req); + BIO_free_all(bp_csr); + BIO_free_all(bp_public); + BIO_free_all(bp_private); + + EVP_PKEY_free(pKey); + BN_free(bne); + if(ret==1) { + Results.CSR = FileToString(CsrPath.path()); + Results.PrivateKey = FileToString(PrivateKey.path()); + Results.PublicKey = FileToString(PubKey.path()); + } + + return ret; + } + + bool VerifyECKey(const std::string &key) { + try { + Poco::TemporaryFile F; + + std::ofstream of(F.path().c_str(), std::ios_base::trunc | std::ios_base::out | std::ios_base::binary); + of << key; + of.close(); + + auto Key = Poco::SharedPtr( + new Poco::Crypto::ECKey("", F.path(),"")); + + return true; + } catch (const Poco::Exception &E) { + + } + return false; + } + + bool VerifyRSAKey([[ + maybe_unused]] const std::string &key) { + try { + Poco::TemporaryFile F; + + std::ofstream of(F.path().c_str(), std::ios_base::trunc | std::ios_base::out | std::ios_base::binary); + of << key; + of.close(); + + auto Key = Poco::SharedPtr( + new Poco::Crypto::RSAKey("", F.path(),"")); + return true; + } catch (const Poco::Exception &E) { + + } + return false; + } + + bool ValidX509Certificate([[ + maybe_unused]] const std::string &Cert) { + try { + Poco::TemporaryFile F; + std::ofstream of(F.path().c_str(), std::ios_base::trunc | std::ios_base::out | std::ios_base::binary); + of << Cert; + of.close(); + + auto Key = Poco::SharedPtr( + new Poco::Crypto::X509Certificate(F.path())); + return true; + } catch (const Poco::Exception &E) { + + } + return false; + } + + bool ValidX509Certificate([[ + maybe_unused]] const std::vector &Certs) { + auto F = [](const std::string &C) -> bool { return ValidX509Certificate(C); }; + return std::all_of(Certs.begin(),Certs.end(), F); + } + + std::string generateStrongPassword(int minLength, int maxLength, int numDigits, int minLowercase, int minSpecial, int minUppercase) { + // Define character sets for each category + const std::string lowercaseChars = "abcdefghijklmnopqrstuvwxyz"; + const std::string uppercaseChars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; + const std::string digitChars = "0123456789"; + const std::string specialChars = "!@#$%^&*()_+[]{}|;:,.<>?"; + + // Check if parameters are valid + if (minLength < 1 || minLength > maxLength || minLowercase + minUppercase + numDigits + minSpecial > maxLength) { + return "Invalid parameters"; + } + + // Initialize random seed + std::random_device rd; + std::mt19937 g(rd()); + + // Initialize the password string + std::string password; + + // Generate the required number of each character type + for (int i = 0; i < minLowercase; ++i) { + password += lowercaseChars[g() % lowercaseChars.length()]; + } + for (int i = 0; i < minUppercase; ++i) { + password += uppercaseChars[g() % uppercaseChars.length()]; + } + for (int i = 0; i < numDigits; ++i) { + password += digitChars[g() % digitChars.length()]; + } + for (int i = 0; i < minSpecial; ++i) { + password += specialChars[g() % specialChars.length()]; + } + + // Calculate how many more characters are needed + int remainingLength = maxLength - (int)password.length(); + + // Generate random characters to fill the remaining length + for (int i = 0; i < remainingLength; ++i) { + int category = g() % 4; // Randomly select a category + if (category == 0) { + password += lowercaseChars[g() % lowercaseChars.length()]; + } else if (category == 1) { + password += uppercaseChars[g() % uppercaseChars.length()]; + } else if (category == 2) { + password += digitChars[g() % digitChars.length()]; + } else { + password += specialChars[g() % specialChars.length()]; + } + } + + // Shuffle the password to randomize the character order + std::shuffle(password.begin(), password.end(),g); + + return password; + } + } // namespace OpenWifi::Utils diff --git a/src/framework/utils.h b/src/framework/utils.h index 3979dca..cf708bd 100644 --- a/src/framework/utils.h +++ b/src/framework/utils.h @@ -247,4 +247,21 @@ namespace OpenWifi::Utils { return count; } + struct CSRCreationParameters { + std::string Country, Province, City, + Organization, CommonName; + int bits=2048; + }; + + struct CSRCreationResults { + std::string CSR, PublicKey, PrivateKey; + }; + + bool CreateX509CSR(const CSRCreationParameters & Parameters, CSRCreationResults & Results); + std::string generateStrongPassword(int minLength, int maxLength, int numDigits, int minLowercase, int minSpecial, int minUppercase); + bool VerifyECKey(const std::string &key); + bool VerifyRSAKey(const std::string &key); + bool ValidX509Certificate(const std::string &Cert); + bool ValidX509Certificate(const std::vector &Certs); + } // namespace OpenWifi::Utils