mirror of
https://github.com/Telecominfraproject/wlan-cloud-ucentralsec.git
synced 2025-11-01 19:27:59 +00:00
New router and simplifiedrest handler
This commit is contained in:
@@ -54,7 +54,6 @@ add_executable( ucentralsec
|
|||||||
src/Daemon.h src/Daemon.cpp
|
src/Daemon.h src/Daemon.cpp
|
||||||
src/MicroService.cpp src/MicroService.h
|
src/MicroService.cpp src/MicroService.h
|
||||||
src/SubSystemServer.cpp src/SubSystemServer.h
|
src/SubSystemServer.cpp src/SubSystemServer.h
|
||||||
src/RESTAPI_unknownRequestHandler.h src/RESTAPI_unknownRequestHandler.cpp
|
|
||||||
src/RESTAPI_oauth2Handler.h src/RESTAPI_oauth2Handler.cpp
|
src/RESTAPI_oauth2Handler.h src/RESTAPI_oauth2Handler.cpp
|
||||||
src/RESTAPI_handler.h src/RESTAPI_handler.cpp
|
src/RESTAPI_handler.h src/RESTAPI_handler.cpp
|
||||||
src/RESTAPI_server.cpp src/RESTAPI_server.h
|
src/RESTAPI_server.cpp src/RESTAPI_server.h
|
||||||
@@ -70,7 +69,8 @@ add_executable( ucentralsec
|
|||||||
src/storage_tables.cpp src/SMTPMailerService.cpp src/SMTPMailerService.h
|
src/storage_tables.cpp src/SMTPMailerService.cpp src/SMTPMailerService.h
|
||||||
src/RESTAPI_users_handler.cpp src/RESTAPI_users_handler.h
|
src/RESTAPI_users_handler.cpp src/RESTAPI_users_handler.h
|
||||||
src/RESTAPI_user_handler.cpp src/RESTAPI_user_handler.h
|
src/RESTAPI_user_handler.cpp src/RESTAPI_user_handler.h
|
||||||
src/RESTAPI_action_links.cpp src/RESTAPI_action_links.h)
|
src/RESTAPI_action_links.cpp src/RESTAPI_action_links.h src/storage_users.cpp
|
||||||
|
src/RESTAPI_systemServices_handler.cpp src/RESTAPI_systemServices_handler.h)
|
||||||
|
|
||||||
target_link_libraries(ucentralsec PUBLIC
|
target_link_libraries(ucentralsec PUBLIC
|
||||||
${Poco_LIBRARIES} ${Boost_LIBRARIES} ${ZLIB_LIBRARIES} ${AWSSDK_LINK_LIBRARIES} CppKafka::cppkafka )
|
${Poco_LIBRARIES} ${Boost_LIBRARIES} ${ZLIB_LIBRARIES} ${AWSSDK_LINK_LIBRARIES} CppKafka::cppkafka )
|
||||||
|
|||||||
@@ -308,6 +308,11 @@ components:
|
|||||||
- instagram
|
- instagram
|
||||||
oauthUserInfo:
|
oauthUserInfo:
|
||||||
type: string
|
type: string
|
||||||
|
securityPolicy:
|
||||||
|
type: string
|
||||||
|
securityPolicyChange:
|
||||||
|
type: integer
|
||||||
|
format: int64
|
||||||
|
|
||||||
UserList:
|
UserList:
|
||||||
type: object
|
type: object
|
||||||
@@ -417,6 +422,29 @@ components:
|
|||||||
items:
|
items:
|
||||||
$ref: '#/components/schemas/SecurityProfile'
|
$ref: '#/components/schemas/SecurityProfile'
|
||||||
|
|
||||||
|
InternalServiceInfo:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
privateURI:
|
||||||
|
type: string
|
||||||
|
publicURI:
|
||||||
|
type: string
|
||||||
|
auth:
|
||||||
|
type: string
|
||||||
|
|
||||||
|
|
||||||
|
InternalSystemServices:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
key:
|
||||||
|
type: string
|
||||||
|
version:
|
||||||
|
type: integer
|
||||||
|
services:
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
|
$ref: '#/components/schemas/InternalServiceInfo'
|
||||||
|
|
||||||
#########################################################################################
|
#########################################################################################
|
||||||
##
|
##
|
||||||
## End of uCentral system wide values
|
## End of uCentral system wide values
|
||||||
@@ -741,6 +769,24 @@ paths:
|
|||||||
404:
|
404:
|
||||||
$ref: '#/components/responses/NotFound'
|
$ref: '#/components/responses/NotFound'
|
||||||
|
|
||||||
|
#########################################################################################
|
||||||
|
## The following calls are restricted to the private system side APIs
|
||||||
|
#########################################################################################
|
||||||
|
/systemServices:
|
||||||
|
get:
|
||||||
|
tags:
|
||||||
|
- Security
|
||||||
|
summary: Retrieve the basic system information. This information is used between services only.
|
||||||
|
operationId: getSystemServices
|
||||||
|
responses:
|
||||||
|
200:
|
||||||
|
$ref: '#/components/schemas/InternalSystemServices'
|
||||||
|
403:
|
||||||
|
$ref: '#/components/responses/Unauthorized'
|
||||||
|
404:
|
||||||
|
$ref: '#/components/responses/NotFound'
|
||||||
|
|
||||||
|
|
||||||
#########################################################################################
|
#########################################################################################
|
||||||
##
|
##
|
||||||
## These are endpoints that all services in the uCentral stack must provide
|
## These are endpoints that all services in the uCentral stack must provide
|
||||||
|
|||||||
4
set_env.sh
Executable file
4
set_env.sh
Executable file
@@ -0,0 +1,4 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
export UCENTRALSEC_CONFIG=`pwd`
|
||||||
|
export UCENTRALSEC_ROOT=`pwd`
|
||||||
@@ -38,9 +38,7 @@ namespace uCentral {
|
|||||||
Types::SubSystemVec{
|
Types::SubSystemVec{
|
||||||
Storage(),
|
Storage(),
|
||||||
RESTAPI_Server(),
|
RESTAPI_Server(),
|
||||||
KafkaManager(),
|
SMTPMailerService()
|
||||||
SMTPMailerService(),
|
|
||||||
ALBHealthCheckServer()
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
return instance_;
|
return instance_;
|
||||||
@@ -49,7 +47,6 @@ namespace uCentral {
|
|||||||
void Daemon::initialize(Poco::Util::Application &self) {
|
void Daemon::initialize(Poco::Util::Application &self) {
|
||||||
MicroService::initialize(*this);
|
MicroService::initialize(*this);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(int argc, char **argv) {
|
int main(int argc, char **argv) {
|
||||||
|
|||||||
@@ -39,14 +39,10 @@ namespace uCentral {
|
|||||||
Types::SubSystemVec SubSystems) :
|
Types::SubSystemVec SubSystems) :
|
||||||
MicroService( PropFile, RootEnv, ConfigEnv, AppName, SubSystems) {};
|
MicroService( PropFile, RootEnv, ConfigEnv, AppName, SubSystems) {};
|
||||||
|
|
||||||
bool AutoProvisioning() const { return AutoProvisioning_ ; }
|
|
||||||
[[nodiscard]] std::string IdentifyDevice(const std::string & Compatible) const;
|
|
||||||
void initialize(Poco::Util::Application &self);
|
void initialize(Poco::Util::Application &self);
|
||||||
static Daemon *instance();
|
static Daemon *instance();
|
||||||
private:
|
private:
|
||||||
static Daemon *instance_;
|
static Daemon *instance_;
|
||||||
bool AutoProvisioning_ = false;
|
|
||||||
Types::StringMapStringSet DeviceTypeIdentifications_;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
inline Daemon * Daemon() { return Daemon::instance(); }
|
inline Daemon * Daemon() { return Daemon::instance(); }
|
||||||
|
|||||||
@@ -38,93 +38,104 @@ namespace uCentral {
|
|||||||
int KafkaManager::Start() {
|
int KafkaManager::Start() {
|
||||||
if(!KafkaEnabled_)
|
if(!KafkaEnabled_)
|
||||||
return 0;
|
return 0;
|
||||||
Running_ = true;
|
ProducerThr_ = std::make_unique<std::thread>([this]() { this->Producer(); });
|
||||||
ProducerThr_ = std::make_unique<std::thread>(Producer,this);
|
ConsumerThr_ = std::make_unique<std::thread>([this]() { this->Consumer(); });
|
||||||
ProducerThr_->detach();
|
|
||||||
ConsumerThr_ = std::make_unique<std::thread>(Consumer,this);
|
|
||||||
ConsumerThr_->detach();
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void KafkaManager::Stop() {
|
void KafkaManager::Stop() {
|
||||||
if(KafkaEnabled_) {
|
if(KafkaEnabled_) {
|
||||||
Running_ = false;
|
ProducerRunning_ = ConsumerRunning_ = false;
|
||||||
ConsumerThr_->join();
|
|
||||||
ProducerThr_->join();
|
ProducerThr_->join();
|
||||||
|
ConsumerThr_->join();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void KafkaManager::Producer(KafkaManager *Mgr) {
|
void KafkaManager::Producer() {
|
||||||
cppkafka::Configuration Config({
|
cppkafka::Configuration Config({
|
||||||
{ "metadata.broker.list", Daemon()->ConfigGetString("ucentral.kafka.brokerlist") } ,
|
{ "metadata.broker.list", Daemon()->ConfigGetString("ucentral.kafka.brokerlist") }
|
||||||
{ "enable.auto.commit", Daemon()->ConfigGetBool("ucentral.kafka.auto.commit", false)}
|
|
||||||
});
|
});
|
||||||
Mgr->SystemInfoWrapper_ = R"lit({ "system" : { "id" : )lit" +
|
SystemInfoWrapper_ = R"lit({ "system" : { "id" : )lit" +
|
||||||
std::to_string(Daemon()->ConfigGetInt("ucentral.system.id")) +
|
std::to_string(Daemon()->ID()) +
|
||||||
R"lit( , "host" : ")lit" + Daemon()->ConfigGetString("ucentral.system.uri") +
|
R"lit( , "host" : ")lit" + Daemon()->PrivateEndPoint() +
|
||||||
R"lit(" } , "payload" : ")lit" ;
|
R"lit(" } , "payload" : ")lit" ;
|
||||||
|
|
||||||
cppkafka::Producer Producer(Config);
|
cppkafka::Producer Producer(Config);
|
||||||
|
ProducerRunning_ = true;
|
||||||
while(Mgr->Running_) {
|
while(ProducerRunning_) {
|
||||||
std::this_thread::sleep_for(std::chrono::milliseconds(2000));
|
std::this_thread::sleep_for(std::chrono::milliseconds(200));
|
||||||
if(!Mgr->Running_)
|
try
|
||||||
break;
|
|
||||||
{
|
{
|
||||||
SubMutexGuard G(Mgr->ProducerMutex_);
|
SubMutexGuard G(ProducerMutex_);
|
||||||
while (!Mgr->Queue_.empty() && Mgr->Running_) {
|
while (!Queue_.empty()) {
|
||||||
const auto M = Mgr->Queue_.front();
|
const auto M = Queue_.front();
|
||||||
// std::cout << "Producing Topic: " << M.Topic << " Key: " << M.Key <<std::endl;
|
|
||||||
Producer.produce(
|
Producer.produce(
|
||||||
cppkafka::MessageBuilder(M.Topic).key(M.Key).payload(M.PayLoad));
|
cppkafka::MessageBuilder(M.Topic).key(M.Key).payload(M.PayLoad));
|
||||||
Mgr->Queue_.pop();
|
Queue_.pop();
|
||||||
}
|
}
|
||||||
// Producer_->flush();
|
Producer.flush();
|
||||||
|
} catch (const cppkafka::HandleException &E ) {
|
||||||
|
Logger_.warning(Poco::format("Caught a Kafka exception (producer): %s",std::string{E.what()}));
|
||||||
|
} catch (const Poco::Exception &E) {
|
||||||
|
Logger_.log(E);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void KafkaManager::Consumer(KafkaManager *Mgr ) {
|
void KafkaManager::Consumer() {
|
||||||
cppkafka::Configuration Config({
|
cppkafka::Configuration Config({
|
||||||
{ "group.id", 1 },
|
{ "group.id", Daemon()->ConfigGetString("ucentral.kafka.group.id") },
|
||||||
{ "enable.auto.commit", Daemon()->ConfigGetBool("ucentral.kafka.auto.commit",false) },
|
{ "enable.auto.commit", Daemon()->ConfigGetBool("ucentral.kafka.auto.commit",false) },
|
||||||
{ "metadata.broker.list", Daemon()->ConfigGetString("ucentral.kafka.brokerlist") }
|
{ "metadata.broker.list", Daemon()->ConfigGetString("ucentral.kafka.brokerlist") },
|
||||||
|
{ "auto.offset.reset", "earliest" } ,
|
||||||
|
{ "enable.partition.eof", false }
|
||||||
});
|
});
|
||||||
|
|
||||||
cppkafka::Consumer Consumer(Config);
|
cppkafka::Consumer Consumer(Config);
|
||||||
|
Consumer.set_assignment_callback([=](const cppkafka::TopicPartitionList& partitions) {
|
||||||
Consumer.set_assignment_callback([Mgr](const cppkafka::TopicPartitionList& partitions) {
|
std::cout << "Partition assigned: " << partitions.front().get_partition() << std::endl;
|
||||||
Mgr->Logger_.information(Poco::format("Got assigned: %Lu...",(uint64_t )partitions.front().get_partition()));
|
Logger_.information(Poco::format("Got assigned: %Lu...",(uint64_t )partitions.front().get_partition()));
|
||||||
});
|
});
|
||||||
Consumer.set_revocation_callback([Mgr](const cppkafka::TopicPartitionList& partitions) {
|
Consumer.set_revocation_callback([this](const cppkafka::TopicPartitionList& partitions) {
|
||||||
Mgr->Logger_.information(Poco::format("Got revoked: %Lu...",(uint64_t )partitions.front().get_partition()));
|
std::cout << "Partition revocation: " << partitions.front().get_partition() << std::endl;
|
||||||
|
Logger_.information(Poco::format("Got revoked: %Lu...",(uint64_t )partitions.front().get_partition()));
|
||||||
});
|
});
|
||||||
|
|
||||||
std::vector<std::string> Topics;
|
Types::StringVec Topics;
|
||||||
for(const auto &i:Mgr->Notifiers_)
|
for(const auto &i:Notifiers_)
|
||||||
Topics.push_back(i.first);
|
Topics.push_back(i.first);
|
||||||
|
|
||||||
Consumer.subscribe(Topics);
|
Consumer.subscribe(Topics);
|
||||||
while(Mgr->Running_) {
|
|
||||||
cppkafka::Message Msg = Consumer.poll(std::chrono::milliseconds(2000));
|
ConsumerRunning_ = true;
|
||||||
if (Msg) {
|
while(ConsumerRunning_) {
|
||||||
|
try {
|
||||||
|
cppkafka::Message Msg = Consumer.poll(std::chrono::milliseconds(200));
|
||||||
|
if (!Msg)
|
||||||
|
continue;;
|
||||||
if (Msg.get_error()) {
|
if (Msg.get_error()) {
|
||||||
if (!Msg.is_eof()) {
|
if (!Msg.is_eof()) {
|
||||||
Mgr->Logger_.error(
|
Logger_.error(Poco::format("Error: %s", Msg.get_error().to_string()));
|
||||||
Poco::format("Error: %s", Msg.get_error().to_string()));
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
SubMutexGuard G(Mgr->ConsumerMutex_);
|
|
||||||
auto It = Mgr->Notifiers_.find(Msg.get_topic());
|
|
||||||
if (It != Mgr->Notifiers_.end()) {
|
|
||||||
Types::TopicNotifyFunctionList &FL = It->second;
|
|
||||||
for (auto &F : FL)
|
|
||||||
F.first(Msg.get_key(), Msg.get_payload());
|
|
||||||
}
|
}
|
||||||
Consumer.commit(Msg);
|
Consumer.commit(Msg);
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
|
SubMutexGuard G(ConsumerMutex_);
|
||||||
|
auto It = Notifiers_.find(Msg.get_topic());
|
||||||
|
if (It != Notifiers_.end()) {
|
||||||
|
Types::TopicNotifyFunctionList &FL = It->second;
|
||||||
|
for (auto &F : FL) {
|
||||||
|
std::string Key{Msg.get_key()};
|
||||||
|
std::string Payload{Msg.get_payload()};
|
||||||
|
std::thread T(F.first, Key, Payload);
|
||||||
|
T.detach();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Consumer.commit(Msg);
|
||||||
|
} catch (const cppkafka::HandleException &E) {
|
||||||
|
Logger_.warning(Poco::format("Caught a Kafka exception (consumer): %s",std::string{E.what()}));
|
||||||
|
} catch (const Poco::Exception &E) {
|
||||||
|
Logger_.log(E);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -133,19 +144,19 @@ namespace uCentral {
|
|||||||
return std::move( SystemInfoWrapper_ + PayLoad + "}");
|
return std::move( SystemInfoWrapper_ + PayLoad + "}");
|
||||||
}
|
}
|
||||||
|
|
||||||
void KafkaManager::PostMessage(std::string topic, std::string key, std::string PayLoad) {
|
void KafkaManager::PostMessage(std::string topic, std::string key, std::string PayLoad, bool WrapMessage ) {
|
||||||
if(KafkaEnabled_ && Running_) {
|
if(KafkaEnabled_) {
|
||||||
SubMutexGuard G(Mutex_);
|
SubMutexGuard G(Mutex_);
|
||||||
|
|
||||||
KMessage M{
|
KMessage M{
|
||||||
.Topic = std::move(topic), .Key = std::move(key), .PayLoad = std::move(WrapSystemId(PayLoad))};
|
.Topic = std::move(topic),
|
||||||
// std::cout << "Posting Topic: " << M.Topic << " Key: " << M.Key << " Payload: " << M.PayLoad << std::endl;
|
.Key = std::move(key),
|
||||||
|
.PayLoad = std::move(WrapMessage ? WrapSystemId(PayLoad) : PayLoad )};
|
||||||
Queue_.push(std::move(M));
|
Queue_.push(std::move(M));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int KafkaManager::RegisterTopicWatcher(const std::string &Topic, Types::TopicNotifyFunction &F) {
|
int KafkaManager::RegisterTopicWatcher(const std::string &Topic, Types::TopicNotifyFunction &F) {
|
||||||
if(!Running_) {
|
if(KafkaEnabled_) {
|
||||||
SubMutexGuard G(Mutex_);
|
SubMutexGuard G(Mutex_);
|
||||||
auto It = Notifiers_.find(Topic);
|
auto It = Notifiers_.find(Topic);
|
||||||
if(It == Notifiers_.end()) {
|
if(It == Notifiers_.end()) {
|
||||||
@@ -162,7 +173,7 @@ namespace uCentral {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void KafkaManager::UnregisterTopicWatcher(const std::string &Topic, int Id) {
|
void KafkaManager::UnregisterTopicWatcher(const std::string &Topic, int Id) {
|
||||||
if(!Running_) {
|
if(KafkaEnabled_) {
|
||||||
SubMutexGuard G(Mutex_);
|
SubMutexGuard G(Mutex_);
|
||||||
auto It = Notifiers_.find(Topic);
|
auto It = Notifiers_.find(Topic);
|
||||||
if(It != Notifiers_.end()) {
|
if(It != Notifiers_.end()) {
|
||||||
|
|||||||
@@ -35,24 +35,26 @@ namespace uCentral {
|
|||||||
return instance_;
|
return instance_;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void Producer(KafkaManager *);
|
void Producer();
|
||||||
static void Consumer(KafkaManager *);
|
void Consumer();
|
||||||
|
|
||||||
int Start() override;
|
int Start() override;
|
||||||
void Stop() override;
|
void Stop() override;
|
||||||
|
|
||||||
void PostMessage(std::string topic, std::string key, std::string payload);
|
void PostMessage(std::string topic, std::string key, std::string payload, bool WrapMessage = true);
|
||||||
[[nodiscard]] std::string WrapSystemId(const std::string & PayLoad);
|
[[nodiscard]] std::string WrapSystemId(const std::string & PayLoad);
|
||||||
[[nodiscard]] bool Enabled() { return Running_ && KafkaEnabled_; }
|
[[nodiscard]] bool Enabled() { return KafkaEnabled_; }
|
||||||
int RegisterTopicWatcher(const std::string &Topic, Types::TopicNotifyFunction & F);
|
int RegisterTopicWatcher(const std::string &Topic, Types::TopicNotifyFunction & F);
|
||||||
void UnregisterTopicWatcher(const std::string &Topic, int FunctionId);
|
void UnregisterTopicWatcher(const std::string &Topic, int FunctionId);
|
||||||
|
void WakeUp();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static KafkaManager *instance_;
|
static KafkaManager *instance_;
|
||||||
SubMutex ProducerMutex_;
|
SubMutex ProducerMutex_;
|
||||||
SubMutex ConsumerMutex_;
|
SubMutex ConsumerMutex_;
|
||||||
bool KafkaEnabled_ = false;
|
bool KafkaEnabled_ = false;
|
||||||
std::atomic_bool Running_ = false;
|
std::atomic_bool ProducerRunning_ = false;
|
||||||
|
std::atomic_bool ConsumerRunning_ = false;
|
||||||
std::queue<KMessage> Queue_;
|
std::queue<KMessage> Queue_;
|
||||||
std::string SystemInfoWrapper_;
|
std::string SystemInfoWrapper_;
|
||||||
std::unique_ptr<std::thread> ConsumerThr_;
|
std::unique_ptr<std::thread> ConsumerThr_;
|
||||||
|
|||||||
17
src/Kafka_topics.h
Normal file
17
src/Kafka_topics.h
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
//
|
||||||
|
// Created by stephane bourque on 2021-06-07.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef UCENTRALGW_KAFKA_TOPICS_H
|
||||||
|
#define UCENTRALGW_KAFKA_TOPICS_H
|
||||||
|
|
||||||
|
namespace uCentral::KafkaTopics {
|
||||||
|
static const std::string HEALTHCHECK{"healthcheck"};
|
||||||
|
static const std::string STATE{"state"};
|
||||||
|
static const std::string CONNECTION{"connection"};
|
||||||
|
static const std::string WIFISCAN{"wifiscan"};
|
||||||
|
static const std::string ALERTS{"alerts"};
|
||||||
|
static const std::string COMMAND{"command"};
|
||||||
|
static const std::string SERVICE_EVENTS{"service_events"};
|
||||||
|
}
|
||||||
|
#endif // UCENTRALGW_KAFKA_TOPICS_H
|
||||||
@@ -17,10 +17,22 @@
|
|||||||
#include "Poco/Path.h"
|
#include "Poco/Path.h"
|
||||||
#include "Poco/File.h"
|
#include "Poco/File.h"
|
||||||
#include "Poco/String.h"
|
#include "Poco/String.h"
|
||||||
|
#include "Poco/JSON/Object.h"
|
||||||
|
#include "Poco/JSON/Parser.h"
|
||||||
|
#include "Poco/JSON/Stringifier.h"
|
||||||
|
|
||||||
|
#include "ALBHealthCheckServer.h"
|
||||||
|
#ifndef SMALL_BUILD
|
||||||
|
#include "KafkaManager.h"
|
||||||
|
#endif
|
||||||
|
#include "Kafka_topics.h"
|
||||||
|
|
||||||
#include "MicroService.h"
|
#include "MicroService.h"
|
||||||
#include "Utils.h"
|
#include "Utils.h"
|
||||||
|
|
||||||
|
#undef DBGLINE
|
||||||
|
#define DBGLINE
|
||||||
|
|
||||||
namespace uCentral {
|
namespace uCentral {
|
||||||
|
|
||||||
void MyErrorHandler::exception(const Poco::Exception & E) {
|
void MyErrorHandler::exception(const Poco::Exception & E) {
|
||||||
@@ -43,7 +55,84 @@ namespace uCentral {
|
|||||||
std::exit(Reason);
|
std::exit(Reason);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MicroService::BusMessageReceived(std::string Key, std::string Message) {
|
||||||
|
SubMutexGuard G(InfraMutex_);
|
||||||
|
// std::cout << "Message arrived:" << Key << " ," << Message << std::endl;
|
||||||
|
try {
|
||||||
|
Poco::JSON::Parser P;
|
||||||
|
auto Object = P.parse(Message).extract<Poco::JSON::Object::Ptr>();
|
||||||
|
if(Object->has("id")) {
|
||||||
|
uint64_t ID = Object->get("id");
|
||||||
|
if(ID!=ID_) {
|
||||||
|
if( Object->has("event") &&
|
||||||
|
Object->has("type") &&
|
||||||
|
Object->has("publicEndPoint") &&
|
||||||
|
Object->has("privateEndPoint") &&
|
||||||
|
Object->has("version") &&
|
||||||
|
Object->has("key")) {
|
||||||
|
auto Event = Object->get("event").toString();
|
||||||
|
|
||||||
|
if(Event == "keep-alive" && Services_.find(ID)!=Services_.end()) {
|
||||||
|
std::cout << "Keep-alive from " << ID << std::endl;
|
||||||
|
Services_[ID].LastUpdate = std::time(nullptr);
|
||||||
|
} else if (Event=="leave") {
|
||||||
|
Services_.erase(ID);
|
||||||
|
std::cout << "Leave from " << ID << std::endl;
|
||||||
|
} else if (Event== "join" || Event=="keep_alive") {
|
||||||
|
std::cout << "Join from " << ID << std::endl;
|
||||||
|
Services_[ID] = MicroServiceMeta{
|
||||||
|
.Id = ID,
|
||||||
|
.Type = Poco::toLower(Object->get("type").toString()),
|
||||||
|
.PrivateEndPoint = Object->get("privateEndPoint").toString(),
|
||||||
|
.PublicEndPoint = Object->get("publicEndPoint").toString(),
|
||||||
|
.AccessKey = Object->get("key").toString(),
|
||||||
|
.Version = Object->get("version").toString(),
|
||||||
|
.LastUpdate = (uint64_t )std::time(nullptr) };
|
||||||
|
for(const auto &[Id,Svc]:Services_)
|
||||||
|
std::cout << "ID:" << Id << " Type:" << Svc.Type << " EndPoint:" << Svc.PublicEndPoint << std::endl;
|
||||||
|
} else {
|
||||||
|
std::cout << "Bad packet 2 ..." << std::endl;
|
||||||
|
logger().error(Poco::format("Malformed event from device %Lu, event=%s", ID, Event));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
std::cout << "Bad packet 1 ..." << std::endl;
|
||||||
|
logger().error(Poco::format("Malformed event from device %Lu", ID));
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
std::cout << "Ignoring my own messages..." << std::endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (const Poco::Exception &E) {
|
||||||
|
DBGLINE
|
||||||
|
logger().log(E);
|
||||||
|
DBGLINE
|
||||||
|
}
|
||||||
|
DBGLINE
|
||||||
|
}
|
||||||
|
|
||||||
|
MicroServiceMetaVec MicroService::GetServices(const std::string & Type) {
|
||||||
|
SubMutexGuard G(InfraMutex_);
|
||||||
|
|
||||||
|
auto T = Poco::toLower(Type);
|
||||||
|
MicroServiceMetaVec Res;
|
||||||
|
for(const auto &[Id,ServiceRec]:Services_) {
|
||||||
|
if(ServiceRec.Type==T)
|
||||||
|
Res.push_back(ServiceRec);
|
||||||
|
}
|
||||||
|
return Res;
|
||||||
|
}
|
||||||
|
|
||||||
void MicroService::initialize(Poco::Util::Application &self) {
|
void MicroService::initialize(Poco::Util::Application &self) {
|
||||||
|
|
||||||
|
std::string V{APP_VERSION};
|
||||||
|
std::string B{BUILD_NUMBER};
|
||||||
|
Version_ = V + "(" + B + ")";
|
||||||
|
|
||||||
|
// add the default services
|
||||||
|
SubSystems_.push_back(KafkaManager());
|
||||||
|
SubSystems_.push_back(ALBHealthCheckServer());
|
||||||
|
|
||||||
Poco::Net::initializeSSL();
|
Poco::Net::initializeSSL();
|
||||||
Poco::Net::HTTPStreamFactory::registerFactory();
|
Poco::Net::HTTPStreamFactory::registerFactory();
|
||||||
Poco::Net::HTTPSStreamFactory::registerFactory();
|
Poco::Net::HTTPSStreamFactory::registerFactory();
|
||||||
@@ -87,9 +176,14 @@ namespace uCentral {
|
|||||||
ID_ = Utils::GetSystemId();
|
ID_ = Utils::GetSystemId();
|
||||||
if(!DebugMode_)
|
if(!DebugMode_)
|
||||||
DebugMode_ = ConfigGetBool("ucentral.system.debug",false);
|
DebugMode_ = ConfigGetBool("ucentral.system.debug",false);
|
||||||
|
MyPrivateEndPoint_ = ConfigGetString("ucentral.system.uri.private");
|
||||||
|
MyPublicEndPoint_ = ConfigGetString("ucentral.system.uri.public");
|
||||||
|
MyHash_ = CreateHash(MyPrivateEndPoint_);
|
||||||
InitializeSubSystemServers();
|
InitializeSubSystemServers();
|
||||||
ServerApplication::initialize(self);
|
ServerApplication::initialize(self);
|
||||||
|
|
||||||
|
Types::TopicNotifyFunction F = [this](std::string s1,std::string s2) { this->BusMessageReceived(s1,s2); };
|
||||||
|
KafkaManager()->RegisterTopicWatcher(KafkaTopics::SERVICE_EVENTS, F);
|
||||||
}
|
}
|
||||||
|
|
||||||
void MicroService::uninitialize() {
|
void MicroService::uninitialize() {
|
||||||
@@ -139,12 +233,6 @@ namespace uCentral {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string MicroService::Version() {
|
|
||||||
std::string V = APP_VERSION;
|
|
||||||
std::string B = BUILD_NUMBER;
|
|
||||||
return V + "(" + B + ")";
|
|
||||||
}
|
|
||||||
|
|
||||||
void MicroService::handleHelp(const std::string &name, const std::string &value) {
|
void MicroService::handleHelp(const std::string &name, const std::string &value) {
|
||||||
HelpRequested_ = true;
|
HelpRequested_ = true;
|
||||||
displayHelp();
|
displayHelp();
|
||||||
@@ -186,9 +274,11 @@ namespace uCentral {
|
|||||||
void MicroService::StartSubSystemServers() {
|
void MicroService::StartSubSystemServers() {
|
||||||
for(auto i:SubSystems_)
|
for(auto i:SubSystems_)
|
||||||
i->Start();
|
i->Start();
|
||||||
|
BusEventManager_.Start();
|
||||||
}
|
}
|
||||||
|
|
||||||
void MicroService::StopSubSystemServers() {
|
void MicroService::StopSubSystemServers() {
|
||||||
|
BusEventManager_.Stop();
|
||||||
for(auto i=SubSystems_.rbegin(); i!=SubSystems_.rend(); ++i)
|
for(auto i=SubSystems_.rbegin(); i!=SubSystems_.rend(); ++i)
|
||||||
(*i)->Stop();
|
(*i)->Stop();
|
||||||
}
|
}
|
||||||
@@ -286,6 +376,58 @@ namespace uCentral {
|
|||||||
return Cipher_->decryptString(S, Poco::Crypto::Cipher::Cipher::ENC_BASE64);;
|
return Cipher_->decryptString(S, Poco::Crypto::Cipher::Cipher::ENC_BASE64);;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string MicroService::CreateHash(const std::string &S) {
|
||||||
|
SHA2_.update(S);
|
||||||
|
return Utils::ToHex(SHA2_.digest());
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string MicroService::MakeSystemEventMessage( const std::string & Type ) const {
|
||||||
|
Poco::JSON::Object Obj;
|
||||||
|
Obj.set("event",Type);
|
||||||
|
Obj.set("id",ID_);
|
||||||
|
Obj.set("type",Poco::toLower(DAEMON_APP_NAME));
|
||||||
|
Obj.set("publicEndPoint",MyPublicEndPoint_);
|
||||||
|
Obj.set("privateEndPoint",MyPrivateEndPoint_);
|
||||||
|
Obj.set("key",MyHash_);
|
||||||
|
Obj.set("version",Version_);
|
||||||
|
std::stringstream ResultText;
|
||||||
|
Poco::JSON::Stringifier::stringify(Obj, ResultText);
|
||||||
|
return ResultText.str();
|
||||||
|
}
|
||||||
|
|
||||||
|
void BusEventManager::run() {
|
||||||
|
|
||||||
|
Running_ = true;
|
||||||
|
|
||||||
|
auto Msg = Daemon()->MakeSystemEventMessage("join");
|
||||||
|
KafkaManager()->PostMessage(KafkaTopics::SERVICE_EVENTS,Daemon()->PrivateEndPoint(),Msg, false);
|
||||||
|
|
||||||
|
while(Running_) {
|
||||||
|
Poco::Thread::trySleep(60000);
|
||||||
|
if(!Running_)
|
||||||
|
break;
|
||||||
|
auto Msg = Daemon()->MakeSystemEventMessage("keep-alive");
|
||||||
|
KafkaManager()->PostMessage(KafkaTopics::SERVICE_EVENTS,Daemon()->PrivateEndPoint(),Msg, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
Msg = Daemon()->MakeSystemEventMessage("leave");
|
||||||
|
KafkaManager()->PostMessage(KafkaTopics::SERVICE_EVENTS,Daemon()->PrivateEndPoint(),Msg, false);
|
||||||
|
};
|
||||||
|
|
||||||
|
void BusEventManager::Start() {
|
||||||
|
if(KafkaManager()->Enabled()) {
|
||||||
|
Thread_.start(*this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void BusEventManager::Stop() {
|
||||||
|
if(KafkaManager()->Enabled()) {
|
||||||
|
Running_ = false;
|
||||||
|
Thread_.wakeUp();
|
||||||
|
Thread_.join();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
int MicroService::main(const ArgVec &args) {
|
int MicroService::main(const ArgVec &args) {
|
||||||
|
|
||||||
MyErrorHandler ErrorHandler(*this);
|
MyErrorHandler ErrorHandler(*this);
|
||||||
@@ -313,7 +455,4 @@ namespace uCentral {
|
|||||||
|
|
||||||
return Application::EXIT_OK;
|
return Application::EXIT_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -20,6 +20,7 @@
|
|||||||
#include "Poco/Crypto/RSAKey.h"
|
#include "Poco/Crypto/RSAKey.h"
|
||||||
#include "Poco/Crypto/CipherFactory.h"
|
#include "Poco/Crypto/CipherFactory.h"
|
||||||
#include "Poco/Crypto/Cipher.h"
|
#include "Poco/Crypto/Cipher.h"
|
||||||
|
#include "Poco/SHA2Engine.h"
|
||||||
|
|
||||||
#include "uCentralTypes.h"
|
#include "uCentralTypes.h"
|
||||||
#include "SubSystemServer.h"
|
#include "SubSystemServer.h"
|
||||||
@@ -36,6 +37,29 @@ namespace uCentral {
|
|||||||
Poco::Util::Application &App_;
|
Poco::Util::Application &App_;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class BusEventManager : public Poco::Runnable {
|
||||||
|
public:
|
||||||
|
void run() override;
|
||||||
|
void Start();
|
||||||
|
void Stop();
|
||||||
|
private:
|
||||||
|
std::atomic_bool Running_ = false;
|
||||||
|
Poco::Thread Thread_;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct MicroServiceMeta {
|
||||||
|
uint64_t Id=0;
|
||||||
|
std::string Type;
|
||||||
|
std::string PrivateEndPoint;
|
||||||
|
std::string PublicEndPoint;
|
||||||
|
std::string AccessKey;
|
||||||
|
std::string Version;
|
||||||
|
uint64_t LastUpdate=0;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef std::map<uint64_t, MicroServiceMeta> MicroServiceMetaMap;
|
||||||
|
typedef std::vector<MicroServiceMeta> MicroServiceMetaVec;
|
||||||
|
|
||||||
class MicroService : public Poco::Util::ServerApplication {
|
class MicroService : public Poco::Util::ServerApplication {
|
||||||
public:
|
public:
|
||||||
explicit MicroService( std::string PropFile,
|
explicit MicroService( std::string PropFile,
|
||||||
@@ -66,7 +90,7 @@ namespace uCentral {
|
|||||||
void StopSubSystemServers();
|
void StopSubSystemServers();
|
||||||
void Exit(int Reason);
|
void Exit(int Reason);
|
||||||
bool SetSubsystemLogLevel(const std::string & SubSystem, const std::string & Level);
|
bool SetSubsystemLogLevel(const std::string & SubSystem, const std::string & Level);
|
||||||
[[nodiscard]] static std::string Version();
|
[[nodiscard]] std::string Version() { return Version_; }
|
||||||
[[nodiscard]] const Poco::SharedPtr<Poco::Crypto::RSAKey> & Key() { return AppKey_; }
|
[[nodiscard]] const Poco::SharedPtr<Poco::Crypto::RSAKey> & Key() { return AppKey_; }
|
||||||
[[nodiscard]] inline const std::string & DataDir() { return DataDir_; }
|
[[nodiscard]] inline const std::string & DataDir() { return DataDir_; }
|
||||||
[[nodiscard]] std::string CreateUUID();
|
[[nodiscard]] std::string CreateUUID();
|
||||||
@@ -85,6 +109,15 @@ namespace uCentral {
|
|||||||
[[nodiscard]] uint64_t ConfigGetBool(const std::string &Key);
|
[[nodiscard]] uint64_t ConfigGetBool(const std::string &Key);
|
||||||
[[nodiscard]] std::string Encrypt(const std::string &S);
|
[[nodiscard]] std::string Encrypt(const std::string &S);
|
||||||
[[nodiscard]] std::string Decrypt(const std::string &S);
|
[[nodiscard]] std::string Decrypt(const std::string &S);
|
||||||
|
[[nodiscard]] std::string CreateHash(const std::string &S);
|
||||||
|
[[nodiscard]] std::string Hash() const { return MyHash_; };
|
||||||
|
[[nodiscard]] std::string ServiceType() const { return DAEMON_APP_NAME; };
|
||||||
|
[[nodiscard]] std::string PrivateEndPoint() const { return MyPrivateEndPoint_; };
|
||||||
|
[[nodiscard]] std::string PublicEndPoint() const { return MyPublicEndPoint_; };
|
||||||
|
[[nodiscard]] std::string MakeSystemEventMessage( const std::string & Type ) const ;
|
||||||
|
|
||||||
|
void BusMessageReceived( std::string Key, std::string Message);
|
||||||
|
[[nodiscard]] MicroServiceMetaVec GetServices(const std::string & type);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool HelpRequested_ = false;
|
bool HelpRequested_ = false;
|
||||||
@@ -98,6 +131,14 @@ namespace uCentral {
|
|||||||
Types::SubSystemVec SubSystems_;
|
Types::SubSystemVec SubSystems_;
|
||||||
Poco::Crypto::CipherFactory & CipherFactory_ = Poco::Crypto::CipherFactory::defaultFactory();
|
Poco::Crypto::CipherFactory & CipherFactory_ = Poco::Crypto::CipherFactory::defaultFactory();
|
||||||
Poco::Crypto::Cipher * Cipher_ = nullptr;
|
Poco::Crypto::Cipher * Cipher_ = nullptr;
|
||||||
|
Poco::SHA2Engine SHA2_;
|
||||||
|
MicroServiceMetaMap Services_;
|
||||||
|
std::string MyHash_;
|
||||||
|
std::string MyPrivateEndPoint_;
|
||||||
|
std::string MyPublicEndPoint_;
|
||||||
|
std::string Version_;
|
||||||
|
BusEventManager BusEventManager_;
|
||||||
|
SubMutex InfraMutex_;
|
||||||
|
|
||||||
std::string DAEMON_PROPERTIES_FILENAME;
|
std::string DAEMON_PROPERTIES_FILENAME;
|
||||||
std::string DAEMON_ROOT_ENV_VAR;
|
std::string DAEMON_ROOT_ENV_VAR;
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ namespace uCentral {
|
|||||||
Poco::Net::HTTPRequest::HTTP_OPTIONS}) {}
|
Poco::Net::HTTPRequest::HTTP_OPTIONS}) {}
|
||||||
void handleRequest(Poco::Net::HTTPServerRequest &Request,
|
void handleRequest(Poco::Net::HTTPServerRequest &Request,
|
||||||
Poco::Net::HTTPServerResponse &Response) override;
|
Poco::Net::HTTPServerResponse &Response) override;
|
||||||
|
static const std::list<const char *> PathName() { return std::list<const char *>{"/api/v1/actions"}; };
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -11,40 +11,46 @@
|
|||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <iterator>
|
#include <iterator>
|
||||||
#include <future>
|
#include <future>
|
||||||
#include <numeric>
|
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
|
|
||||||
#include "Poco/URI.h"
|
#include "Poco/URI.h"
|
||||||
#include "Poco/DateTimeParser.h"
|
|
||||||
|
|
||||||
#include "RESTAPI_handler.h"
|
|
||||||
#include "AuthService.h"
|
#include "AuthService.h"
|
||||||
|
#include "RESTAPI_handler.h"
|
||||||
#include "RESTAPI_protocol.h"
|
#include "RESTAPI_protocol.h"
|
||||||
#include "Utils.h"
|
#include "Utils.h"
|
||||||
|
|
||||||
#define DBG std::cout << __LINE__ << " " __FILE__ << std::endl;
|
#define DBG std::cout << __LINE__ << " " __FILE__ << std::endl;
|
||||||
|
|
||||||
namespace uCentral {
|
namespace uCentral {
|
||||||
bool RESTAPIHandler::ParseBindings(const std::string & Request, const std::string & Path, BindingMap &bindings) {
|
|
||||||
|
bool RESTAPIHandler::ParseBindings(const std::string & Request, const std::list<const char *> & EndPoints, BindingMap &bindings) {
|
||||||
std::string Param, Value;
|
std::string Param, Value;
|
||||||
|
|
||||||
bindings.clear();
|
bindings.clear();
|
||||||
std::vector<std::string> PathItems = uCentral::Utils::Split(Path,'/');
|
std::vector<std::string> PathItems = uCentral::Utils::Split(Request, '/');
|
||||||
std::vector<std::string> ParamItems = uCentral::Utils::Split(Request,'/');
|
|
||||||
|
|
||||||
if(PathItems.size()!=ParamItems.size())
|
for(const auto &EndPoint:EndPoints) {
|
||||||
return false;
|
std::vector<std::string> ParamItems = uCentral::Utils::Split(EndPoint, '/');
|
||||||
|
if (PathItems.size() != ParamItems.size())
|
||||||
|
continue;
|
||||||
|
|
||||||
for(auto i=0;i!=PathItems.size();i++) {
|
bool Matched = true;
|
||||||
if (PathItems[i] != ParamItems[i]) {
|
for (auto i = 0; i != PathItems.size() && Matched; i++) {
|
||||||
if (PathItems[i][0] == '{') {
|
// std::cout << "PATH:" << PathItems[i] << " ENDPOINT:" << ParamItems[i] << std::endl;
|
||||||
auto ParamName = PathItems[i].substr(1, PathItems[i].size() - 2);
|
if (PathItems[i] != ParamItems[i]) {
|
||||||
bindings[ParamName] = ParamItems[i];
|
if (ParamItems[i][0] == '{') {
|
||||||
} else
|
auto ParamName = ParamItems[i].substr(1, ParamItems[i].size() - 2);
|
||||||
return false;
|
bindings[ParamName] = PathItems[i];
|
||||||
|
} else {
|
||||||
|
Matched = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
if(Matched)
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
return true;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void RESTAPIHandler::PrintBindings() {
|
void RESTAPIHandler::PrintBindings() {
|
||||||
@@ -242,7 +248,7 @@ namespace uCentral {
|
|||||||
|
|
||||||
bool RESTAPIHandler::IsAuthorized(Poco::Net::HTTPServerRequest &Request,
|
bool RESTAPIHandler::IsAuthorized(Poco::Net::HTTPServerRequest &Request,
|
||||||
Poco::Net::HTTPServerResponse &Response) {
|
Poco::Net::HTTPServerResponse &Response) {
|
||||||
if (AuthService()->IsAuthorized(Request, SessionToken_, UserInfo_)) {
|
if (uCentral::AuthService()->IsAuthorized(Request, SessionToken_, UserInfo_)) {
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
UnAuthorized(Request, Response);
|
UnAuthorized(Request, Response);
|
||||||
@@ -253,7 +259,7 @@ namespace uCentral {
|
|||||||
bool RESTAPIHandler::IsAuthorized(Poco::Net::HTTPServerRequest &Request,
|
bool RESTAPIHandler::IsAuthorized(Poco::Net::HTTPServerRequest &Request,
|
||||||
Poco::Net::HTTPServerResponse &Response, std::string &UserName) {
|
Poco::Net::HTTPServerResponse &Response, std::string &UserName) {
|
||||||
|
|
||||||
if (AuthService()->IsAuthorized(Request, SessionToken_, UserInfo_)) {
|
if (uCentral::AuthService()->IsAuthorized(Request, SessionToken_, UserInfo_)) {
|
||||||
UserName = UserInfo_.username_;
|
UserName = UserInfo_.username_;
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -19,25 +19,24 @@
|
|||||||
#include "Poco/File.h"
|
#include "Poco/File.h"
|
||||||
#include "Poco/JSON/Object.h"
|
#include "Poco/JSON/Object.h"
|
||||||
|
|
||||||
#include "RESTAPI_objects.h"
|
|
||||||
#include "AuthService.h"
|
#include "AuthService.h"
|
||||||
|
#include "RESTAPI_objects.h"
|
||||||
|
|
||||||
namespace uCentral {
|
namespace uCentral {
|
||||||
|
|
||||||
struct QueryBlock {
|
|
||||||
uint64_t StartDate = 0 , EndDate = 0 , Offset = 0 , Limit = 0, LogType = 0 ;
|
|
||||||
std::string SerialNumber, Filter, Select;
|
|
||||||
bool Lifetime=false, LastOnly=false, Newest=false;
|
|
||||||
};
|
|
||||||
|
|
||||||
class RESTAPIHandler : public Poco::Net::HTTPRequestHandler {
|
class RESTAPIHandler : public Poco::Net::HTTPRequestHandler {
|
||||||
public:
|
public:
|
||||||
|
struct QueryBlock {
|
||||||
|
uint64_t StartDate = 0 , EndDate = 0 , Offset = 0 , Limit = 0, LogType = 0 ;
|
||||||
|
std::string SerialNumber, Filter, Select;
|
||||||
|
bool Lifetime=false, LastOnly=false, Newest=false;
|
||||||
|
};
|
||||||
typedef std::map<std::string, std::string> BindingMap;
|
typedef std::map<std::string, std::string> BindingMap;
|
||||||
|
|
||||||
RESTAPIHandler(BindingMap map, Poco::Logger &l, std::vector<std::string> Methods)
|
RESTAPIHandler(BindingMap map, Poco::Logger &l, std::vector<std::string> Methods)
|
||||||
: Bindings_(std::move(map)), Logger_(l), Methods_(std::move(Methods)) {}
|
: Bindings_(std::move(map)), Logger_(l), Methods_(std::move(Methods)) {}
|
||||||
|
|
||||||
static bool ParseBindings(const std::string & Path, const std::string & Request, BindingMap &Keys);
|
static bool ParseBindings(const std::string & Request, const std::list<const char *> & EndPoints, BindingMap &Keys);
|
||||||
void PrintBindings();
|
void PrintBindings();
|
||||||
void ParseParameters(Poco::Net::HTTPServerRequest &request);
|
void ParseParameters(Poco::Net::HTTPServerRequest &request);
|
||||||
|
|
||||||
@@ -94,14 +93,52 @@ namespace uCentral {
|
|||||||
[[nodiscard]] static uint64_t GetWhen(const Poco::JSON::Object::Ptr &Obj);
|
[[nodiscard]] static uint64_t GetWhen(const Poco::JSON::Object::Ptr &Obj);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
BindingMap Bindings_;
|
BindingMap Bindings_;
|
||||||
Poco::URI::QueryParameters Parameters_;
|
Poco::URI::QueryParameters Parameters_;
|
||||||
Poco::Logger &Logger_;
|
Poco::Logger &Logger_;
|
||||||
std::string SessionToken_;
|
std::string SessionToken_;
|
||||||
struct uCentral::Objects::WebToken UserInfo_;
|
struct uCentral::Objects::WebToken UserInfo_;
|
||||||
std::vector<std::string> Methods_;
|
std::vector<std::string> Methods_;
|
||||||
QueryBlock QB_;
|
QueryBlock QB_;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class RESTAPI_UnknownRequestHandler : public RESTAPIHandler {
|
||||||
|
public:
|
||||||
|
RESTAPI_UnknownRequestHandler(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L)
|
||||||
|
: RESTAPIHandler(bindings, L, std::vector<std::string>{}) {}
|
||||||
|
void handleRequest(Poco::Net::HTTPServerRequest &Request,
|
||||||
|
Poco::Net::HTTPServerResponse &Response) override {
|
||||||
|
if (!IsAuthorized(Request, Response))
|
||||||
|
return;
|
||||||
|
BadRequest(Request, Response);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<class T>
|
||||||
|
constexpr auto test_has_PathName_method(T*)
|
||||||
|
-> decltype( T::PathName() , std::true_type{} )
|
||||||
|
{
|
||||||
|
return std::true_type{};
|
||||||
|
}
|
||||||
|
constexpr auto test_has_PathName_method(...) -> std::false_type
|
||||||
|
{
|
||||||
|
return std::false_type{};
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T, typename... Args>
|
||||||
|
RESTAPIHandler * RESTAPI_Router(const std::string & RequestedPath, RESTAPIHandler::BindingMap &Bindings, Poco::Logger & Logger) {
|
||||||
|
static_assert(test_has_PathName_method((T*)nullptr), "Class must have a static PathName() method.");
|
||||||
|
if(RESTAPIHandler::ParseBindings(RequestedPath,T::PathName(),Bindings)) {
|
||||||
|
return new T(Bindings, Logger);
|
||||||
|
}
|
||||||
|
|
||||||
|
if constexpr (sizeof...(Args) == 0) {
|
||||||
|
return new RESTAPI_UnknownRequestHandler(Bindings,Logger);
|
||||||
|
} else {
|
||||||
|
return RESTAPI_Router<Args...>(RequestedPath, Bindings, Logger);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif //UCENTRAL_RESTAPI_HANDLER_H
|
#endif //UCENTRAL_RESTAPI_HANDLER_H
|
||||||
|
|||||||
@@ -8,55 +8,57 @@
|
|||||||
|
|
||||||
#include "Poco/JSON/Parser.h"
|
#include "Poco/JSON/Parser.h"
|
||||||
|
|
||||||
|
#include "AuthService.h"
|
||||||
#include "RESTAPI_oauth2Handler.h"
|
#include "RESTAPI_oauth2Handler.h"
|
||||||
#include "RESTAPI_protocol.h"
|
#include "RESTAPI_protocol.h"
|
||||||
#include "AuthService.h"
|
|
||||||
|
|
||||||
namespace uCentral {
|
namespace uCentral {
|
||||||
void RESTAPI_oauth2Handler::handleRequest(Poco::Net::HTTPServerRequest &Request,
|
void RESTAPI_oauth2Handler::handleRequest(Poco::Net::HTTPServerRequest &Request,
|
||||||
Poco::Net::HTTPServerResponse &Response) {
|
Poco::Net::HTTPServerResponse &Response) {
|
||||||
if (!ContinueProcessing(Request, Response))
|
|
||||||
return;
|
|
||||||
|
|
||||||
try {
|
if (!ContinueProcessing(Request, Response))
|
||||||
if (Request.getMethod() == Poco::Net::HTTPServerRequest::HTTP_POST) {
|
return;
|
||||||
|
|
||||||
// Extract the info for login...
|
try {
|
||||||
Poco::JSON::Parser parser;
|
if (Request.getMethod() == Poco::Net::HTTPServerRequest::HTTP_POST) {
|
||||||
Poco::JSON::Object::Ptr Obj = parser.parse(Request.stream()).extract<Poco::JSON::Object::Ptr>();
|
|
||||||
|
|
||||||
auto userId = GetS(uCentral::RESTAPI::Protocol::USERID, Obj);
|
// Extract the info for login...
|
||||||
auto password = GetS(uCentral::RESTAPI::Protocol::PASSWORD, Obj);
|
Poco::JSON::Parser parser;
|
||||||
|
Poco::JSON::Object::Ptr Obj =
|
||||||
|
parser.parse(Request.stream()).extract<Poco::JSON::Object::Ptr>();
|
||||||
|
|
||||||
Poco::toLowerInPlace(userId);
|
auto userId = GetS(uCentral::RESTAPI::Protocol::USERID, Obj);
|
||||||
uCentral::Objects::WebToken Token;
|
auto password = GetS(uCentral::RESTAPI::Protocol::PASSWORD, Obj);
|
||||||
|
|
||||||
if (AuthService()->Authorize(userId, password, Token)) {
|
Poco::toLowerInPlace(userId);
|
||||||
Poco::JSON::Object ReturnObj;
|
uCentral::Objects::WebToken Token;
|
||||||
Token.to_json(ReturnObj);
|
|
||||||
ReturnObject(Request, ReturnObj, Response);
|
if (AuthService()->Authorize(userId, password, Token)) {
|
||||||
} else {
|
Poco::JSON::Object ReturnObj;
|
||||||
UnAuthorized(Request, Response);
|
Token.to_json(ReturnObj);
|
||||||
}
|
ReturnObject(Request, ReturnObj, Response);
|
||||||
} else if (Request.getMethod() == Poco::Net::HTTPServerRequest::HTTP_DELETE) {
|
} else {
|
||||||
if (!IsAuthorized(Request, Response)) {
|
UnAuthorized(Request, Response);
|
||||||
return;
|
}
|
||||||
}
|
} else if (Request.getMethod() == Poco::Net::HTTPServerRequest::HTTP_DELETE) {
|
||||||
auto Token = GetBinding(uCentral::RESTAPI::Protocol::TOKEN, "...");
|
if (!IsAuthorized(Request, Response)) {
|
||||||
if (Token == SessionToken_) {
|
return;
|
||||||
AuthService()->Logout(Token);
|
}
|
||||||
ReturnStatus(Request, Response, Poco::Net::HTTPResponse::HTTP_NO_CONTENT, true);
|
auto Token = GetBinding(uCentral::RESTAPI::Protocol::TOKEN, "...");
|
||||||
} else {
|
if (Token == SessionToken_) {
|
||||||
NotFound(Request, Response);
|
AuthService()->Logout(Token);
|
||||||
}
|
ReturnStatus(Request, Response, Poco::Net::HTTPResponse::HTTP_NO_CONTENT, true);
|
||||||
} else {
|
} else {
|
||||||
BadRequest(Request, Response);
|
NotFound(Request, Response);
|
||||||
}
|
}
|
||||||
return;
|
} else {
|
||||||
}
|
BadRequest(Request, Response);
|
||||||
catch (const Poco::Exception &E) {
|
}
|
||||||
Logger_.warning(Poco::format("%s: Failed with: %s", std::string(__func__), E.displayText()));
|
return;
|
||||||
}
|
} catch (const Poco::Exception &E) {
|
||||||
BadRequest(Request, Response);
|
Logger_.warning(
|
||||||
}
|
Poco::format("%s: Failed with: %s", std::string(__func__), E.displayText()));
|
||||||
|
}
|
||||||
|
BadRequest(Request, Response);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -12,17 +12,16 @@
|
|||||||
#include "RESTAPI_handler.h"
|
#include "RESTAPI_handler.h"
|
||||||
|
|
||||||
namespace uCentral {
|
namespace uCentral {
|
||||||
class RESTAPI_oauth2Handler : public uCentral::RESTAPIHandler {
|
class RESTAPI_oauth2Handler : public RESTAPIHandler {
|
||||||
public:
|
public:
|
||||||
RESTAPI_oauth2Handler(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L)
|
RESTAPI_oauth2Handler(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L)
|
||||||
: RESTAPIHandler(bindings, L,
|
: RESTAPIHandler(bindings, L,
|
||||||
std::vector<std::string>
|
std::vector<std::string>{Poco::Net::HTTPRequest::HTTP_POST,
|
||||||
{Poco::Net::HTTPRequest::HTTP_POST,
|
Poco::Net::HTTPRequest::HTTP_DELETE,
|
||||||
Poco::Net::HTTPRequest::HTTP_DELETE,
|
Poco::Net::HTTPRequest::HTTP_OPTIONS}) {}
|
||||||
Poco::Net::HTTPRequest::HTTP_OPTIONS}) {}
|
void handleRequest(Poco::Net::HTTPServerRequest &request,
|
||||||
|
Poco::Net::HTTPServerResponse &response) override;
|
||||||
void handleRequest(Poco::Net::HTTPServerRequest &request, Poco::Net::HTTPServerResponse &response) override;
|
static const std::list<const char *> PathName() { return std::list<const char *>{"/api/v1/oauth2/{token}","/api/v1/oauth2"}; };
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif //UCENTRAL_RESTAPI_OAUTH2HANDLER_H
|
#endif //UCENTRAL_RESTAPI_OAUTH2HANDLER_H
|
||||||
|
|||||||
@@ -8,11 +8,7 @@
|
|||||||
|
|
||||||
#include "Poco/JSON/Parser.h"
|
#include "Poco/JSON/Parser.h"
|
||||||
#include "Poco/JSON/Stringifier.h"
|
#include "Poco/JSON/Stringifier.h"
|
||||||
|
|
||||||
#include "Daemon.h"
|
|
||||||
#include "RESTAPI_handler.h"
|
|
||||||
#include "RESTAPI_objects.h"
|
#include "RESTAPI_objects.h"
|
||||||
#include "Utils.h"
|
|
||||||
|
|
||||||
namespace uCentral::Objects {
|
namespace uCentral::Objects {
|
||||||
|
|
||||||
@@ -44,5 +40,94 @@ namespace uCentral::Objects {
|
|||||||
Obj.set("username",username_);
|
Obj.set("username",username_);
|
||||||
Obj.set("aclTemplate",AclTemplateObj);
|
Obj.set("aclTemplate",AclTemplateObj);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void UserInfo::to_json(Poco::JSON::Object &Obj) const {
|
||||||
|
Obj.set("Id",Id);
|
||||||
|
Obj.set("name",name);
|
||||||
|
Obj.set("description", description);
|
||||||
|
Obj.set("avatar", avatar);
|
||||||
|
Obj.set("email", email);
|
||||||
|
Obj.set("validated", validated);
|
||||||
|
Obj.set("validationEmail", validationEmail);
|
||||||
|
Obj.set("validationDate", validationDate);
|
||||||
|
Obj.set("creationDate", creationDate);
|
||||||
|
Obj.set("validationURI", validationURI);
|
||||||
|
Obj.set("changePassword", changePassword);
|
||||||
|
Obj.set("lastLogin", lastLogin);
|
||||||
|
Obj.set("currentLoginURI", currentLoginURI);
|
||||||
|
Obj.set("lastPasswordChange", lastPasswordChange);
|
||||||
|
Obj.set("lastEmailCheck", lastEmailCheck);
|
||||||
|
Obj.set("waitingForEmailCheck", waitingForEmailCheck);
|
||||||
|
Obj.set("locale", locale);
|
||||||
|
Obj.set("notes", notes);
|
||||||
|
Obj.set("location", location);
|
||||||
|
Obj.set("owner", owner);
|
||||||
|
Obj.set("suspended", suspended);
|
||||||
|
Obj.set("blackListed", blackListed);
|
||||||
|
Obj.set("userRole", userRole);
|
||||||
|
Obj.set("userTypeProprietaryInfo", userTypeProprietaryInfo);
|
||||||
|
Obj.set("securityPolicy", securityPolicy);
|
||||||
|
Obj.set("securityPolicyChange", securityPolicyChange);
|
||||||
|
};
|
||||||
|
|
||||||
|
bool UserInfo::from_json(Poco::JSON::Object::Ptr Obj) {
|
||||||
|
try {
|
||||||
|
if(Obj->has("Id"))
|
||||||
|
Id = Obj->get("Id");
|
||||||
|
if(Obj->has("name"))
|
||||||
|
name = Obj->get("name").toString();
|
||||||
|
if(Obj->has("description"))
|
||||||
|
description = Obj->get("description").toString();
|
||||||
|
if(Obj->has("avatar"))
|
||||||
|
avatar = Obj->get("avatar").toString();
|
||||||
|
if(Obj->has("email"))
|
||||||
|
email = Obj->get("email").toString();
|
||||||
|
if(Obj->has("validationEmail"))
|
||||||
|
validationEmail = Obj->get("validationEmail").toString();
|
||||||
|
if(Obj->has("validationURI"))
|
||||||
|
validationURI = Obj->get("validationURI").toString();
|
||||||
|
if(Obj->has("currentLoginURI"))
|
||||||
|
currentLoginURI = Obj->get("currentLoginURI").toString();
|
||||||
|
if(Obj->has("locale"))
|
||||||
|
locale = Obj->get("locale").toString();
|
||||||
|
if(Obj->has("notes"))
|
||||||
|
notes = Obj->get("notes").toString();
|
||||||
|
if(Obj->has("userRole"))
|
||||||
|
userRole = Obj->get("userRole").toString();
|
||||||
|
if(Obj->has("securityPolicy"))
|
||||||
|
securityPolicy = Obj->get("securityPolicy").toString();
|
||||||
|
if(Obj->has("userTypeProprietaryInfo"))
|
||||||
|
description = Obj->get("userTypeProprietaryInfo").toString();
|
||||||
|
if(Obj->has("description"))
|
||||||
|
description = Obj->get("description").toString();
|
||||||
|
if(Obj->has("validationDate"))
|
||||||
|
validationDate = Obj->get("validationDate");
|
||||||
|
if(Obj->has("creationDate"))
|
||||||
|
creationDate = Obj->get("creationDate");
|
||||||
|
if(Obj->has("lastLogin"))
|
||||||
|
lastLogin = Obj->get("lastLogin");
|
||||||
|
if(Obj->has("lastPasswordChange"))
|
||||||
|
lastPasswordChange = Obj->get("lastPasswordChange");
|
||||||
|
if(Obj->has("lastEmailCheck"))
|
||||||
|
lastEmailCheck = Obj->get("lastEmailCheck");
|
||||||
|
if(Obj->has("securityPolicyChange"))
|
||||||
|
securityPolicyChange = Obj->get("securityPolicyChange");
|
||||||
|
if(Obj->has("validated"))
|
||||||
|
validated = (Obj->get("validated").toString() == "true");
|
||||||
|
if(Obj->has("changePassword"))
|
||||||
|
changePassword = (Obj->get("changePassword").toString() == "true");
|
||||||
|
if(Obj->has("waitingForEmailCheck"))
|
||||||
|
waitingForEmailCheck = (Obj->get("waitingForEmailCheck").toString() == "true");
|
||||||
|
if(Obj->has("suspended"))
|
||||||
|
suspended = (Obj->get("suspended").toString() == "true");
|
||||||
|
if(Obj->has("blackListed"))
|
||||||
|
blackListed = (Obj->get("blackListed").toString() == "true");
|
||||||
|
return true;
|
||||||
|
} catch (const Poco::Exception &E) {
|
||||||
|
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -13,27 +13,61 @@
|
|||||||
|
|
||||||
namespace uCentral::Objects {
|
namespace uCentral::Objects {
|
||||||
|
|
||||||
struct AclTemplate {
|
struct AclTemplate {
|
||||||
bool Read_ = true ;
|
bool Read_ = true;
|
||||||
bool ReadWrite_ = true ;
|
bool ReadWrite_ = true;
|
||||||
bool ReadWriteCreate_ = true ;
|
bool ReadWriteCreate_ = true;
|
||||||
bool Delete_ = true ;
|
bool Delete_ = true;
|
||||||
bool PortalLogin_ = true ;
|
bool PortalLogin_ = true;
|
||||||
void to_json(Poco::JSON::Object &Obj) const ;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct WebToken {
|
void to_json(Poco::JSON::Object &Obj) const;
|
||||||
std::string access_token_;
|
};
|
||||||
std::string refresh_token_;
|
|
||||||
std::string id_token_;
|
struct WebToken {
|
||||||
std::string token_type_;
|
std::string access_token_;
|
||||||
std::string username_;
|
std::string refresh_token_;
|
||||||
unsigned int expires_in_;
|
std::string id_token_;
|
||||||
unsigned int idle_timeout_;
|
std::string token_type_;
|
||||||
AclTemplate acl_template_;
|
std::string username_;
|
||||||
uint64_t created_;
|
unsigned int expires_in_;
|
||||||
void to_json(Poco::JSON::Object &Obj) const ;
|
unsigned int idle_timeout_;
|
||||||
};
|
AclTemplate acl_template_;
|
||||||
|
uint64_t created_;
|
||||||
|
|
||||||
|
void to_json(Poco::JSON::Object &Obj) const;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct UserInfo {
|
||||||
|
uint64_t Id = 0;
|
||||||
|
std::string name;
|
||||||
|
std::string description;
|
||||||
|
std::string avatar;
|
||||||
|
std::string email;
|
||||||
|
bool validated = false;
|
||||||
|
std::string validationEmail;
|
||||||
|
uint64_t validationDate = 0;
|
||||||
|
uint64_t creationDate = 0;
|
||||||
|
std::string validationURI;
|
||||||
|
bool changePassword = true;
|
||||||
|
uint64_t lastLogin = 0;
|
||||||
|
std::string currentLoginURI;
|
||||||
|
uint64_t lastPasswordChange = 0;
|
||||||
|
uint64_t lastEmailCheck = 0;
|
||||||
|
bool waitingForEmailCheck = false;
|
||||||
|
std::string locale;
|
||||||
|
std::string notes;
|
||||||
|
std::string location;
|
||||||
|
std::string owner;
|
||||||
|
bool suspended = false;
|
||||||
|
bool blackListed = false;
|
||||||
|
std::string userRole;
|
||||||
|
std::string userTypeProprietaryInfo;
|
||||||
|
std::string securityPolicy;
|
||||||
|
uint64_t securityPolicyChange;
|
||||||
|
|
||||||
|
void to_json(Poco::JSON::Object &Obj) const;
|
||||||
|
bool from_json(Poco::JSON::Object::Ptr Obj);
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif //UCENTRAL_RESTAPI_OBJECTS_H
|
#endif //UCENTRAL_RESTAPI_OBJECTS_H
|
||||||
|
|||||||
@@ -10,7 +10,6 @@
|
|||||||
|
|
||||||
#include "RESTAPI_server.h"
|
#include "RESTAPI_server.h"
|
||||||
#include "RESTAPI_oauth2Handler.h"
|
#include "RESTAPI_oauth2Handler.h"
|
||||||
#include "RESTAPI_unknownRequestHandler.h"
|
|
||||||
#include "RESTAPI_system_command.h"
|
#include "RESTAPI_system_command.h"
|
||||||
#include "RESTAPI_user_handler.h"
|
#include "RESTAPI_user_handler.h"
|
||||||
#include "RESTAPI_users_handler.h"
|
#include "RESTAPI_users_handler.h"
|
||||||
@@ -58,24 +57,15 @@ namespace uCentral {
|
|||||||
|
|
||||||
Poco::URI uri(Request.getURI());
|
Poco::URI uri(Request.getURI());
|
||||||
const auto & Path = uri.getPath();
|
const auto & Path = uri.getPath();
|
||||||
RESTAPIHandler::BindingMap bindings;
|
RESTAPIHandler::BindingMap Bindings;
|
||||||
|
|
||||||
if (RESTAPIHandler::ParseBindings(Path, "/api/v1/oauth2/{token}", bindings)) {
|
return RESTAPI_Router<
|
||||||
return new RESTAPI_oauth2Handler(bindings, Logger_);
|
RESTAPI_oauth2Handler,
|
||||||
} else if (RESTAPIHandler::ParseBindings(Path, "/api/v1/oauth2", bindings)) {
|
RESTAPI_users_handler,
|
||||||
return new RESTAPI_oauth2Handler(bindings, Logger_);
|
RESTAPI_user_handler,
|
||||||
} else if (RESTAPIHandler::ParseBindings(Path, "/api/v1/users", bindings)) {
|
RESTAPI_system_command,
|
||||||
return new RESTAPI_users_handler(bindings, Logger_);
|
RESTAPI_action_links
|
||||||
} else if (RESTAPIHandler::ParseBindings(Path, "/api/v1/user", bindings)) {
|
>(Path,Bindings,Logger_);
|
||||||
return new RESTAPI_user_handler(bindings, Logger_);
|
|
||||||
} else if (RESTAPIHandler::ParseBindings(Path, "/api/v1/system", bindings)) {
|
|
||||||
return new RESTAPI_system_command(bindings, Logger_);
|
|
||||||
} else if (RESTAPIHandler::ParseBindings(Path, "/api/v1/actions", bindings)) {
|
|
||||||
return new RESTAPI_action_links(bindings, Logger_);
|
|
||||||
}
|
|
||||||
|
|
||||||
Logger_.error(Poco::format("INVALID-API-ENDPOINT: %s",Path));
|
|
||||||
return new RESTAPI_UnknownRequestHandler(bindings,Logger_);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void RESTAPI_Server::Stop() {
|
void RESTAPI_Server::Stop() {
|
||||||
|
|||||||
11
src/RESTAPI_systemServices_handler.cpp
Normal file
11
src/RESTAPI_systemServices_handler.cpp
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
//
|
||||||
|
// Created by stephane bourque on 2021-06-28.
|
||||||
|
//
|
||||||
|
|
||||||
|
#include "RESTAPI_systemServices_handler.h"
|
||||||
|
|
||||||
|
namespace uCentral {
|
||||||
|
void RESTAPI_systemServices_handler::handleRequest(Poco::Net::HTTPServerRequest &Request, Poco::Net::HTTPServerResponse &Response) {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
27
src/RESTAPI_systemServices_handler.h
Normal file
27
src/RESTAPI_systemServices_handler.h
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
//
|
||||||
|
// Created by stephane bourque on 2021-06-28.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef UCENTRALSEC_RESTAPI_SYSTEMSERVICES_HANDLER_H
|
||||||
|
#define UCENTRALSEC_RESTAPI_SYSTEMSERVICES_HANDLER_H
|
||||||
|
|
||||||
|
#include "RESTAPI_handler.h"
|
||||||
|
|
||||||
|
namespace uCentral {
|
||||||
|
class RESTAPI_systemServices_handler : public RESTAPIHandler {
|
||||||
|
public:
|
||||||
|
RESTAPI_systemServices_handler(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L)
|
||||||
|
: RESTAPIHandler(bindings, L,
|
||||||
|
std::vector<std::string>
|
||||||
|
{Poco::Net::HTTPRequest::HTTP_POST,
|
||||||
|
Poco::Net::HTTPRequest::HTTP_GET,
|
||||||
|
Poco::Net::HTTPRequest::HTTP_PUT,
|
||||||
|
Poco::Net::HTTPRequest::HTTP_DELETE,
|
||||||
|
Poco::Net::HTTPRequest::HTTP_OPTIONS}) {}
|
||||||
|
void handleRequest(Poco::Net::HTTPServerRequest &Request, Poco::Net::HTTPServerResponse &Response) override;
|
||||||
|
private:
|
||||||
|
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif //UCENTRALSEC_RESTAPI_SYSTEMSERVICES_HANDLER_H
|
||||||
@@ -20,6 +20,7 @@ class RESTAPI_system_command : public RESTAPIHandler {
|
|||||||
Poco::Net::HTTPRequest::HTTP_OPTIONS}) {}
|
Poco::Net::HTTPRequest::HTTP_OPTIONS}) {}
|
||||||
void handleRequest(Poco::Net::HTTPServerRequest &request,
|
void handleRequest(Poco::Net::HTTPServerRequest &request,
|
||||||
Poco::Net::HTTPServerResponse &response) override;
|
Poco::Net::HTTPServerResponse &response) override;
|
||||||
|
static const std::list<const char *> PathName() { return std::list<const char *>{"/api/v1/system"}; };
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
#endif // UCENTRALGW_RESTAPI_SYSTEM_COMMAND_H
|
#endif // UCENTRALGW_RESTAPI_SYSTEM_COMMAND_H
|
||||||
|
|||||||
@@ -1,16 +0,0 @@
|
|||||||
//
|
|
||||||
// License type: BSD 3-Clause License
|
|
||||||
// License copy: https://github.com/Telecominfraproject/wlan-cloud-ucentralgw/blob/master/LICENSE
|
|
||||||
//
|
|
||||||
// Created by Stephane Bourque on 2021-03-04.
|
|
||||||
// Arilia Wireless Inc.
|
|
||||||
//
|
|
||||||
|
|
||||||
#include "RESTAPI_unknownRequestHandler.h"
|
|
||||||
|
|
||||||
void RESTAPI_UnknownRequestHandler::handleRequest(Poco::Net::HTTPServerRequest& Request, Poco::Net::HTTPServerResponse& Response)
|
|
||||||
{
|
|
||||||
if(!IsAuthorized(Request,Response))
|
|
||||||
return;
|
|
||||||
BadRequest(Request, Response);
|
|
||||||
}
|
|
||||||
@@ -1,25 +0,0 @@
|
|||||||
//
|
|
||||||
// License type: BSD 3-Clause License
|
|
||||||
// License copy: https://github.com/Telecominfraproject/wlan-cloud-ucentralgw/blob/master/LICENSE
|
|
||||||
//
|
|
||||||
// Created by Stephane Bourque on 2021-03-04.
|
|
||||||
// Arilia Wireless Inc.
|
|
||||||
//
|
|
||||||
|
|
||||||
#ifndef UCENTRAL_RESTAPI_UNKNOWNREQUESTHANDLER_H
|
|
||||||
#define UCENTRAL_RESTAPI_UNKNOWNREQUESTHANDLER_H
|
|
||||||
|
|
||||||
#include "RESTAPI_handler.h"
|
|
||||||
|
|
||||||
class RESTAPI_UnknownRequestHandler: public uCentral::RESTAPIHandler
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
RESTAPI_UnknownRequestHandler(const RESTAPIHandler::BindingMap & bindings,Poco::Logger & L)
|
|
||||||
: RESTAPIHandler(bindings,L,
|
|
||||||
std::vector<std::string>{}) {}
|
|
||||||
void handleRequest(Poco::Net::HTTPServerRequest& request, Poco::Net::HTTPServerResponse& response) override;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#endif //UCENTRAL_RESTAPI_UNKNOWNREQUESTHANDLER_H
|
|
||||||
@@ -19,6 +19,8 @@ namespace uCentral {
|
|||||||
Poco::Net::HTTPRequest::HTTP_DELETE,
|
Poco::Net::HTTPRequest::HTTP_DELETE,
|
||||||
Poco::Net::HTTPRequest::HTTP_OPTIONS}) {}
|
Poco::Net::HTTPRequest::HTTP_OPTIONS}) {}
|
||||||
void handleRequest(Poco::Net::HTTPServerRequest &Request, Poco::Net::HTTPServerResponse &Response) override;
|
void handleRequest(Poco::Net::HTTPServerRequest &Request, Poco::Net::HTTPServerResponse &Response) override;
|
||||||
|
static const std::list<const char *> PathName() { return std::list<const char *>{"/api/v1/user/{id}"}; };
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -16,8 +16,7 @@ namespace uCentral {
|
|||||||
{Poco::Net::HTTPRequest::HTTP_GET,
|
{Poco::Net::HTTPRequest::HTTP_GET,
|
||||||
Poco::Net::HTTPRequest::HTTP_OPTIONS}) {}
|
Poco::Net::HTTPRequest::HTTP_OPTIONS}) {}
|
||||||
void handleRequest(Poco::Net::HTTPServerRequest &Request, Poco::Net::HTTPServerResponse &Response) override;
|
void handleRequest(Poco::Net::HTTPServerRequest &Request, Poco::Net::HTTPServerResponse &Response) override;
|
||||||
private:
|
static const std::list<const char *> PathName() { return std::list<const char *>{"/api/v1/users"}; };
|
||||||
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -45,6 +45,39 @@ namespace uCentral {
|
|||||||
PASSWORD_INVALID
|
PASSWORD_INVALID
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum USER_TYPE {
|
||||||
|
UNKNOWN, ROOT, ADMIN, SUBSCRIBER, CSR, SYSTEM, SPECIAL
|
||||||
|
};
|
||||||
|
|
||||||
|
static USER_TYPE to_userType(const std::string &U) {
|
||||||
|
if (U=="root")
|
||||||
|
return ROOT;
|
||||||
|
else if (U=="admin")
|
||||||
|
return ADMIN;
|
||||||
|
else if (U=="subscriber")
|
||||||
|
return SUBSCRIBER;
|
||||||
|
else if (U=="csr")
|
||||||
|
return CSR;
|
||||||
|
else if (U=="system")
|
||||||
|
return SYSTEM;
|
||||||
|
else if (U=="SPECIAL")
|
||||||
|
return SPECIAL;
|
||||||
|
return UNKNOWN;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const std::string from_userType(USER_TYPE U) {
|
||||||
|
switch(U) {
|
||||||
|
case ROOT: return "root";
|
||||||
|
case ADMIN: return "admin";
|
||||||
|
case SUBSCRIBER: return "subscriber";
|
||||||
|
case CSR: return "csr";
|
||||||
|
case SYSTEM: return "system";
|
||||||
|
case SPECIAL: return "special";
|
||||||
|
case UNKNOWN:
|
||||||
|
default: return "unknown";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static Storage *instance() {
|
static Storage *instance() {
|
||||||
if (instance_ == nullptr) {
|
if (instance_ == nullptr) {
|
||||||
instance_ = new Storage;
|
instance_ = new Storage;
|
||||||
@@ -55,9 +88,25 @@ namespace uCentral {
|
|||||||
int Start() override;
|
int Start() override;
|
||||||
void Stop() override;
|
void Stop() override;
|
||||||
|
|
||||||
int CreateUser(const std::string & Admin, const std::string &UserName, const std::string &Password);
|
// all passwords passed here are all plaintext
|
||||||
bool DeleteUser(const std::string & Admin, const std::string &UserName);
|
bool CreateUser(const std::string & Admin, uCentral::Objects::UserInfo & NewUser);
|
||||||
bool ChangePassword(const std::string & Admin, const std::string &UserName, const std::string &OldPassword, const std::string &NewPassword);
|
bool DeleteUser(const std::string & Admin, uint64_t Id);
|
||||||
|
bool SetOwner(const std::string & Admin, uint64_t Id, const std::string &Owner);
|
||||||
|
bool SetLocation(const std::string & Admin, uint64_t Id, const std::string &Location);
|
||||||
|
AUTH_ERROR ChangePassword(const std::string & Admin, uint64_t Id, const std::string &OldPassword, const std::string &NewPassword);
|
||||||
|
bool AddNotes(const std::string & Admin, uint64_t Id, const std::string &Notes);
|
||||||
|
bool SetPolicyChange(const std::string & Admin, const std::string &NewPolicy);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
bool IdentityExists(std::string & Identity, AuthService::ACCESS_TYPE Type);
|
bool IdentityExists(std::string & Identity, AuthService::ACCESS_TYPE Type);
|
||||||
bool AddIdentity(std::string & Identity, std::string & Password, AuthService::ACCESS_TYPE Type, uCentral::Objects::AclTemplate & ACL);
|
bool AddIdentity(std::string & Identity, std::string & Password, AuthService::ACCESS_TYPE Type, uCentral::Objects::AclTemplate & ACL);
|
||||||
|
|||||||
@@ -360,12 +360,13 @@ namespace uCentral::Utils {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
uint64_t InitializeSystemId() {
|
uint64_t InitializeSystemId() {
|
||||||
uint64_t R = ~ std::rand();
|
std::srand(std::time(nullptr));
|
||||||
auto S = GetDefaultMacAsInt64() ^ R;
|
auto S = GetDefaultMacAsInt64() ^ std::rand();
|
||||||
SaveSystemId(S);
|
SaveSystemId(S);
|
||||||
return S;
|
std::cout << "ID: " << S << std::endl;
|
||||||
}
|
return S;
|
||||||
|
}
|
||||||
|
|
||||||
uint64_t GetSystemId() {
|
uint64_t GetSystemId() {
|
||||||
uint64_t ID=0;
|
uint64_t ID=0;
|
||||||
|
|||||||
@@ -14,6 +14,8 @@
|
|||||||
|
|
||||||
#include "Poco/Net/NetworkInterface.h"
|
#include "Poco/Net/NetworkInterface.h"
|
||||||
|
|
||||||
|
#define DBGLINE { std::cout << __FILE__ << ":" << __func__ << ":" << __LINE__ << std::endl; };
|
||||||
|
|
||||||
namespace uCentral::Utils {
|
namespace uCentral::Utils {
|
||||||
|
|
||||||
[[nodiscard]] std::vector<std::string> Split(const std::string &List, char Delimiter=',');
|
[[nodiscard]] std::vector<std::string> Split(const std::string &List, char Delimiter=',');
|
||||||
|
|||||||
@@ -41,7 +41,9 @@ namespace uCentral {
|
|||||||
"owner varchar, "
|
"owner varchar, "
|
||||||
"suspended int, "
|
"suspended int, "
|
||||||
"blackListed int, "
|
"blackListed int, "
|
||||||
"userType varchar, "
|
"userRole varchar, "
|
||||||
|
"securityPolicy text, "
|
||||||
|
"securityPolicyChange bigint, "
|
||||||
"userTypeProprietaryInfo text"
|
"userTypeProprietaryInfo text"
|
||||||
" ,INDEX emailindex (email ASC)"
|
" ,INDEX emailindex (email ASC)"
|
||||||
" ,INDEX nameindex (name ASC))",
|
" ,INDEX nameindex (name ASC))",
|
||||||
@@ -72,7 +74,9 @@ namespace uCentral {
|
|||||||
"owner varchar, "
|
"owner varchar, "
|
||||||
"suspended int, "
|
"suspended int, "
|
||||||
"blackListed int, "
|
"blackListed int, "
|
||||||
"userType varchar, "
|
"userRole varchar, "
|
||||||
|
"securityPolicy text, "
|
||||||
|
"securityPolicyChange bigint, "
|
||||||
"userTypeProprietaryInfo text"
|
"userTypeProprietaryInfo text"
|
||||||
")",
|
")",
|
||||||
Poco::Data::Keywords::now;
|
Poco::Data::Keywords::now;
|
||||||
|
|||||||
38
src/storage_users.cpp
Normal file
38
src/storage_users.cpp
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
//
|
||||||
|
// Created by stephane bourque on 2021-06-25.
|
||||||
|
//
|
||||||
|
|
||||||
|
#include "StorageService.h"
|
||||||
|
|
||||||
|
namespace uCentral {
|
||||||
|
|
||||||
|
bool Storage::CreateUser(const std::string & Admin, uCentral::Objects::UserInfo & NewUser) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Storage::DeleteUser(const std::string & Admin, uint64_t Id) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Storage::SetOwner(const std::string & Admin, uint64_t Id, const std::string &Owner) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Storage::SetLocation(const std::string & Admin, uint64_t Id, const std::string &Location) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
Storage::AUTH_ERROR Storage::ChangePassword(const std::string & Admin, uint64_t Id, const std::string &OldPassword, const std::string &NewPassword) {
|
||||||
|
return SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Storage::AddNotes(const std::string & Admin, uint64_t Id, const std::string &Notes) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Storage::SetPolicyChange(const std::string & Admin, const std::string &NewPolicy) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
@@ -19,7 +19,7 @@ namespace uCentral::Types {
|
|||||||
typedef std::vector<std::string> StringVec;
|
typedef std::vector<std::string> StringVec;
|
||||||
typedef std::vector<SubSystemServer*> SubSystemVec;
|
typedef std::vector<SubSystemServer*> SubSystemVec;
|
||||||
typedef std::map<std::string,std::set<std::string>> StringMapStringSet;
|
typedef std::map<std::string,std::set<std::string>> StringMapStringSet;
|
||||||
typedef std::function<void(std::string,std::string)> TopicNotifyFunction;
|
typedef std::function<void(std::string, std::string)> TopicNotifyFunction;
|
||||||
typedef std::list<std::pair<TopicNotifyFunction,int>> TopicNotifyFunctionList;
|
typedef std::list<std::pair<TopicNotifyFunction,int>> TopicNotifyFunctionList;
|
||||||
typedef std::map<std::string, TopicNotifyFunctionList> NotifyTable;
|
typedef std::map<std::string, TopicNotifyFunctionList> NotifyTable;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ ucentral.restapi.host.0.backlog = 100
|
|||||||
ucentral.restapi.host.0.security = relaxed
|
ucentral.restapi.host.0.security = relaxed
|
||||||
ucentral.restapi.host.0.rootca = $UCENTRALSEC_ROOT/certs/restapi-ca.pem
|
ucentral.restapi.host.0.rootca = $UCENTRALSEC_ROOT/certs/restapi-ca.pem
|
||||||
ucentral.restapi.host.0.address = *
|
ucentral.restapi.host.0.address = *
|
||||||
ucentral.restapi.host.0.port = 16001
|
ucentral.restapi.host.0.port = 16002
|
||||||
ucentral.restapi.host.0.cert = $UCENTRALSEC_ROOT/certs/restapi-cert.pem
|
ucentral.restapi.host.0.cert = $UCENTRALSEC_ROOT/certs/restapi-cert.pem
|
||||||
ucentral.restapi.host.0.key = $UCENTRALSEC_ROOT/certs/restapi-key.pem
|
ucentral.restapi.host.0.key = $UCENTRALSEC_ROOT/certs/restapi-key.pem
|
||||||
ucentral.restapi.host.0.key.password = mypassword
|
ucentral.restapi.host.0.key.password = mypassword
|
||||||
@@ -27,14 +27,12 @@ authentication.default.username = tip@ucentral.com
|
|||||||
authentication.default.password = openwifi
|
authentication.default.password = openwifi
|
||||||
authentication.default.access = master
|
authentication.default.access = master
|
||||||
authentication.service.type = internal
|
authentication.service.type = internal
|
||||||
firmware.autoupdate.policy.default = auto
|
|
||||||
system.directory.data = $UCENTRALSEC_ROOT/data
|
system.directory.data = $UCENTRALSEC_ROOT/data
|
||||||
|
|
||||||
ucentral.service.key = $UCENTRALSEC_ROOT/certs/restapi-key.pem
|
ucentral.service.key = $UCENTRALSEC_ROOT/certs/restapi-key.pem
|
||||||
ucentral.system.debug = true
|
ucentral.system.debug = true
|
||||||
ucentral.system.uri = https://localhost:16001
|
ucentral.system.uri = https://localhost:16002
|
||||||
ucentral.system.id = 1
|
ucentral.system.commandchannel = /tmp/app.ucentralsec
|
||||||
ucentral.system.commandchannel = /tmp/app.ucentralgw
|
|
||||||
|
|
||||||
mailer.hostname = smtp.gmail.com
|
mailer.hostname = smtp.gmail.com
|
||||||
mailer.username = no-reply@arilia.com
|
mailer.username = no-reply@arilia.com
|
||||||
@@ -45,8 +43,9 @@ mailer.port = 587
|
|||||||
#
|
#
|
||||||
# Kafka
|
# Kafka
|
||||||
#
|
#
|
||||||
ucentral.kafka.enable = false
|
ucentral.kafka.group.id = 3
|
||||||
ucentral.kafka.brokerlist = 127.0.0.1:9092
|
ucentral.kafka.enable = true
|
||||||
|
ucentral.kafka.brokerlist = a1.arilia.com:9092
|
||||||
ucentral.kafka.auto.commit = false
|
ucentral.kafka.auto.commit = false
|
||||||
ucentral.kafka.queue.buffering.max.ms = 50
|
ucentral.kafka.queue.buffering.max.ms = 50
|
||||||
|
|
||||||
@@ -60,7 +59,7 @@ storage.type = sqlite
|
|||||||
#storage.type = mysql
|
#storage.type = mysql
|
||||||
#storage.type = odbc
|
#storage.type = odbc
|
||||||
|
|
||||||
storage.type.sqlite.db = $UCENTRALSEC_ROOT/security.db
|
storage.type.sqlite.db = security.db
|
||||||
storage.type.sqlite.idletime = 120
|
storage.type.sqlite.idletime = 120
|
||||||
storage.type.sqlite.maxsessions = 128
|
storage.type.sqlite.maxsessions = 128
|
||||||
|
|
||||||
@@ -91,11 +90,11 @@ authentication.default.password = 13268b7daa751240369d125e79c873bd8dd3bef7981bdf
|
|||||||
authentication.default.access = master
|
authentication.default.access = master
|
||||||
authentication.service.type = internal
|
authentication.service.type = internal
|
||||||
|
|
||||||
system.directory.data = $UCENTRALSEC_ROOT/data
|
ucentral.system.data = $UCENTRALSEC_ROOT/data
|
||||||
|
|
||||||
ucentral.system.debug = true
|
ucentral.system.debug = true
|
||||||
ucentral.system.uri = https://localhost:16001
|
ucentral.system.uri.private = https://localhost:16002
|
||||||
ucentral.system.commandchannel = /tmp/app.ucentralgw
|
ucentral.system.uri.public = https://local.dpaas.arilia.com:16002
|
||||||
|
ucentral.system.commandchannel = /tmp/app.ucentralsec
|
||||||
|
|
||||||
# email.includeonly = mydomain.com
|
# email.includeonly = mydomain.com
|
||||||
# email.exclude = gmail.com
|
# email.exclude = gmail.com
|
||||||
|
|||||||
Reference in New Issue
Block a user