stephb9959
2023-01-26 21:14:57 -08:00
parent d5e0687ade
commit 0b35942ef6
8 changed files with 902 additions and 398 deletions

View File

@@ -43,8 +43,8 @@ find_package(OpenSSL REQUIRED)
find_package(ZLIB REQUIRED) find_package(ZLIB REQUIRED)
find_package(Poco REQUIRED COMPONENTS Crypto JWT Net Util NetSSL Data DataSQLite) find_package(Poco REQUIRED COMPONENTS Crypto JWT Net Util NetSSL Data DataSQLite)
find_package(nlohmann_json REQUIRED) find_package(nlohmann_json REQUIRED)
find_package(nlohmann_json_schema_validator REQUIRED)
find_package(fmt REQUIRED) find_package(fmt REQUIRED)
find_package(valijson REQUIRED)
if(SMALL_BUILD) if(SMALL_BUILD)
find_package(Poco REQUIRED COMPONENTS Crypto JWT Net Util NetSSL Data DataSQLite) find_package(Poco REQUIRED COMPONENTS Crypto JWT Net Util NetSSL Data DataSQLite)
@@ -210,6 +210,5 @@ target_link_libraries(owprov PUBLIC
${MySQL_LIBRARIES} ${MySQL_LIBRARIES}
${ZLIB_LIBRARIES} ${ZLIB_LIBRARIES}
CppKafka::cppkafka CppKafka::cppkafka
fmt::fmt fmt::fmt)
nlohmann_json_schema_validator)

2
build
View File

@@ -1 +1 @@
6 10

View File

@@ -87,8 +87,8 @@ namespace OpenWifi{
} }
auto Config=RawObject->get("configuration").toString(); auto Config=RawObject->get("configuration").toString();
Poco::JSON::Object Answer; Poco::JSON::Object Answer;
std::string Error; std::vector<std::string> Error;
auto Res = ValidateUCentralConfiguration(Config,Error); auto Res = ValidateUCentralConfiguration(Config,Error, GetBoolParameter("strict",true));
Answer.set("valid",Res); Answer.set("valid",Res);
Answer.set("error", Error); Answer.set("error", Error);
return ReturnObject(Answer); return ReturnObject(Answer);
@@ -124,9 +124,9 @@ namespace OpenWifi{
return BadRequest(RESTAPI::Errors::InvalidDeviceTypes); return BadRequest(RESTAPI::Errors::InvalidDeviceTypes);
} }
RESTAPI::Errors::msg Error; std::vector<std::string> Errors;
if(!ValidateConfigBlock(NewObject,Error)) { if(!ValidateConfigBlock(NewObject,Errors)) {
return BadRequest(Error); return BadRequest(RESTAPI::Errors::ConfigBlockInvalid);
} }
if(DB_.CreateRecord(NewObject)) { if(DB_.CreateRecord(NewObject)) {
@@ -171,9 +171,9 @@ namespace OpenWifi{
if(!NewObject.deviceTypes.empty()) if(!NewObject.deviceTypes.empty())
Existing.deviceTypes = NewObject.deviceTypes; Existing.deviceTypes = NewObject.deviceTypes;
RESTAPI::Errors::msg Error; std::vector<std::string> Errors;
if(!ValidateConfigBlock( NewObject,Error)) { if(!ValidateConfigBlock( NewObject,Errors)) {
return BadRequest(Error); return BadRequest(RESTAPI::Errors::ConfigBlockInvalid);
} }
if(RawObject->has("configuration")) { if(RawObject->has("configuration")) {

View File

@@ -406,7 +406,7 @@ namespace OpenWifi {
return EntityDB::RootUUID(); return EntityDB::RootUUID();
} }
inline bool ValidateConfigBlock(const ProvObjects::DeviceConfiguration &Config, RESTAPI::Errors::msg & Error) { inline bool ValidateConfigBlock(const ProvObjects::DeviceConfiguration &Config, std::vector<std::string> &Errors) {
static const std::vector<std::string> SectionNames{ "globals", "interfaces", "metrics", "radios", "services", static const std::vector<std::string> SectionNames{ "globals", "interfaces", "metrics", "radios", "services",
"unit", "definitions", "ethernet", "switch", "config-raw", "unit", "definitions", "ethernet", "switch", "config-raw",
"third-party" }; "third-party" };
@@ -414,8 +414,7 @@ namespace OpenWifi {
for(const auto &i:Config.configuration) { for(const auto &i:Config.configuration) {
Poco::JSON::Parser P; Poco::JSON::Parser P;
if(i.name.empty()) { if(i.name.empty()) {
std::cout << "Name is empty" << std::endl; Errors.push_back("Name is empty");
Error = RESTAPI::Errors::NameMustBeSet;
return false; return false;
} }
@@ -424,25 +423,23 @@ namespace OpenWifi {
auto N = Blocks->getNames(); auto N = Blocks->getNames();
for (const auto &j: N) { for (const auto &j: N) {
if (std::find(SectionNames.cbegin(), SectionNames.cend(), j) == SectionNames.cend()) { if (std::find(SectionNames.cbegin(), SectionNames.cend(), j) == SectionNames.cend()) {
Error = RESTAPI::Errors::UnknownConfigurationSection; Errors.push_back("Unknown block name");
return false; return false;
} }
} }
} catch (const Poco::JSON::JSONException &E ) { } catch (const Poco::JSON::JSONException &E ) {
Error = RESTAPI::Errors::InvalidJSONDocument; Errors.push_back("Invalid JSON document");
return false; return false;
} }
try { try {
std::string ErrorText; if (ValidateUCentralConfiguration(i.configuration, Errors,true)) {
if (ValidateUCentralConfiguration(i.configuration, ErrorText)) {
// std::cout << "Block: " << i.name << " is valid" << std::endl; // std::cout << "Block: " << i.name << " is valid" << std::endl;
} else { } else {
Error = RESTAPI::Errors::ConfigBlockInvalid ;
return false; return false;
} }
} catch(...) { } catch(...) {
std::cout << "Exception in validation" << std::endl; Errors.push_back("Invalid configuration caused an exception");
return false; return false;
} }
@@ -450,12 +447,11 @@ namespace OpenWifi {
return true; return true;
} }
template <typename Type> std::map<std::string,std::string> CreateObjects(Type & NewObject, RESTAPIHandler & R, RESTAPI::Errors::msg & Error) { template <typename Type> std::map<std::string,std::string> CreateObjects(Type & NewObject, RESTAPIHandler & R, std::vector<std::string> & Errors) {
std::map<std::string,std::string> Result; std::map<std::string,std::string> Result;
auto createObjects = R.GetParameter("createObjects",""); auto createObjects = R.GetParameter("createObjects","");
if(!createObjects.empty()) { if(!createObjects.empty()) {
std::cout << "createObjects: " << createObjects << std::endl;
Poco::JSON::Parser P; Poco::JSON::Parser P;
auto Objects = P.parse(createObjects).extract<Poco::JSON::Object::Ptr>(); auto Objects = P.parse(createObjects).extract<Poco::JSON::Object::Ptr>();
if(Objects->isArray("objects")) { if(Objects->isArray("objects")) {
@@ -467,7 +463,6 @@ namespace OpenWifi {
ProvObjects::Location LC; ProvObjects::Location LC;
if (LC.from_json(LocationDetails)) { if (LC.from_json(LocationDetails)) {
if constexpr(std::is_same_v<Type,ProvObjects::Venue>) { if constexpr(std::is_same_v<Type,ProvObjects::Venue>) {
std::cout << "Location decoded: " << LC.info.name << std::endl;
std::string ParentEntity = FindParentEntity(NewObject); std::string ParentEntity = FindParentEntity(NewObject);
ProvObjects::CreateObjectInfo(R.UserInfo_.userinfo, LC.info); ProvObjects::CreateObjectInfo(R.UserInfo_.userinfo, LC.info);
LC.entity = ParentEntity; LC.entity = ParentEntity;
@@ -479,7 +474,6 @@ namespace OpenWifi {
} }
} }
if constexpr(std::is_same_v<Type,ProvObjects::Operator>) { if constexpr(std::is_same_v<Type,ProvObjects::Operator>) {
std::cout << "Location decoded: " << LC.info.name << std::endl;
std::string ParentEntity = FindParentEntity(NewObject); std::string ParentEntity = FindParentEntity(NewObject);
ProvObjects::CreateObjectInfo(R.UserInfo_.userinfo, LC.info); ProvObjects::CreateObjectInfo(R.UserInfo_.userinfo, LC.info);
LC.entity = ParentEntity; LC.entity = ParentEntity;
@@ -491,7 +485,7 @@ namespace OpenWifi {
} }
} }
} else { } else {
Error = RESTAPI::Errors::InvalidJSONDocument; Errors.push_back("Invalid JSON document");
break; break;
} }
} else if (Object->has("contact")) { } else if (Object->has("contact")) {
@@ -507,10 +501,9 @@ namespace OpenWifi {
ProvObjects::DeviceConfiguration DC; ProvObjects::DeviceConfiguration DC;
if(DC.from_json(ConfigurationDetails)) { if(DC.from_json(ConfigurationDetails)) {
if constexpr(std::is_same_v<Type, ProvObjects::InventoryTag>) { if constexpr(std::is_same_v<Type, ProvObjects::InventoryTag>) {
if(!ValidateConfigBlock(DC,Error)) { if(!ValidateConfigBlock(DC,Errors)) {
break; break;
} }
std::cout << "Configuration decoded: " << DC.info.name << std::endl;
ProvObjects::CreateObjectInfo(R.UserInfo_.userinfo, DC.info); ProvObjects::CreateObjectInfo(R.UserInfo_.userinfo, DC.info);
if (StorageService()->ConfigurationDB().CreateRecord(DC)) { if (StorageService()->ConfigurationDB().CreateRecord(DC)) {
NewObject.deviceConfiguration = DC.info.id; NewObject.deviceConfiguration = DC.info.id;
@@ -518,7 +511,7 @@ namespace OpenWifi {
} }
} }
} else { } else {
Error = RESTAPI::Errors::InvalidJSONDocument; Errors.push_back("Invalid JSON document");
break; break;
} }
} }

View File

@@ -239,10 +239,10 @@ namespace OpenWifi{
return BadRequest(RESTAPI::Errors::UnknownManagementPolicyUUID); return BadRequest(RESTAPI::Errors::UnknownManagementPolicyUUID);
} }
RESTAPI::Errors::msg Error=RESTAPI::Errors::SUCCESS; std::vector<std::string> Errors;
auto ObjectsCreated = CreateObjects(NewObject,*this,Error); auto ObjectsCreated = CreateObjects(NewObject,*this,Errors);
if(Error.err_num != 0) { if(!Errors.empty()) {
return BadRequest(Error); return BadRequest(RESTAPI::Errors::ConfigBlockInvalid);
} }
if(DB_.CreateRecord(NewObject)) { if(DB_.CreateRecord(NewObject)) {
@@ -396,10 +396,10 @@ namespace OpenWifi{
Existing.state = NewObject.state; Existing.state = NewObject.state;
} }
RESTAPI::Errors::msg Error=RESTAPI::Errors::SUCCESS; std::vector<std::string> Errors;
auto ObjectsCreated = CreateObjects(NewObject,*this,Error); auto ObjectsCreated = CreateObjects(NewObject,*this,Errors);
if(Error.err_num != 0) { if(!Errors.empty()) {
return BadRequest(Error); return BadRequest(RESTAPI::Errors::ConfigBlockInvalid);
} }
if(!ObjectsCreated.empty()) { if(!ObjectsCreated.empty()) {

View File

@@ -185,9 +185,10 @@ namespace OpenWifi{
NewObject.children.clear(); NewObject.children.clear();
RESTAPI::Errors::msg Error=RESTAPI::Errors::SUCCESS; RESTAPI::Errors::msg Error=RESTAPI::Errors::SUCCESS;
auto ObjectsCreated = CreateObjects(NewObject,*this,Error); std::vector<std::string> Errors;
auto ObjectsCreated = CreateObjects(NewObject,*this,Errors);
if(Error.err_num != 0) { if(Error.err_num != 0) {
return BadRequest(Error); return BadRequest(RESTAPI::Errors::InternalError);
} }
if(DB_.CreateRecord(NewObject)) { if(DB_.CreateRecord(NewObject)) {
@@ -355,10 +356,10 @@ namespace OpenWifi{
NewObject.parent = Existing.parent; NewObject.parent = Existing.parent;
NewObject.entity = Existing.entity; NewObject.entity = Existing.entity;
RESTAPI::Errors::msg Error=RESTAPI::Errors::SUCCESS; std::vector<std::string> Errors;
auto ObjectsCreated = CreateObjects(NewObject,*this,Error); auto ObjectsCreated = CreateObjects(NewObject,*this,Errors);
if(Error.err_num != 0) { if(!Errors.empty()) {
return BadRequest(Error); return BadRequest(RESTAPI::Errors::ConfigBlockInvalid);
} }
if(!ObjectsCreated.empty()) { if(!ObjectsCreated.empty()) {

File diff suppressed because it is too large Load Diff

View File

@@ -4,11 +4,15 @@
#pragma once #pragma once
#include <nlohmann/json-schema.hpp>
#include "framework/SubSystemServer.h" #include "framework/SubSystemServer.h"
using nlohmann::json; #include <valijson/adapters/poco_json_adapter.hpp>
using nlohmann::json_schema::json_validator; #include <valijson/utils/poco_json_utils.hpp>
#include <valijson/schema.hpp>
#include <valijson/schema_parser.hpp>
#include <valijson/validator.hpp>
#include <valijson/constraints/constraint.hpp>
#include <valijson/constraints/constraint_visitor.hpp>
namespace OpenWifi { namespace OpenWifi {
class ConfigurationValidator : public SubSystemServer { class ConfigurationValidator : public SubSystemServer {
@@ -19,17 +23,19 @@ namespace OpenWifi {
return instance_; return instance_;
} }
bool Validate(const std::string &C, std::string &Error); bool Validate(const std::string &C, std::vector<std::string> &Errors, bool Strict);
static void my_format_checker(const std::string &format, const std::string &value);
int Start() override; int Start() override;
void Stop() override; void Stop() override;
void reinitialize(Poco::Util::Application &self) override; void reinitialize(Poco::Util::Application &self) override;
private: private:
bool Initialized_=false; bool Initialized_=false;
bool Working_=false; bool Working_=false;
void Init(); void Init();
nlohmann::json RootSchema_; std::unique_ptr<valijson::Schema> RootSchema_;
std::unique_ptr<valijson::SchemaParser> SchemaParser_;
std::unique_ptr<valijson::adapters::PocoJsonAdapter> PocoJsonAdapter_;
Poco::JSON::Object::Ptr SchemaDocPtr_;
ConfigurationValidator(): ConfigurationValidator():
SubSystemServer("ConfigValidator", "CFG-VALIDATOR", "config.validator") { SubSystemServer("ConfigValidator", "CFG-VALIDATOR", "config.validator") {
@@ -37,6 +43,6 @@ namespace OpenWifi {
}; };
inline auto ConfigurationValidator() { return ConfigurationValidator::instance(); } inline auto ConfigurationValidator() { return ConfigurationValidator::instance(); }
inline bool ValidateUCentralConfiguration(const std::string &C, std::string &Error) { return ConfigurationValidator::instance()->Validate(C, Error); } inline bool ValidateUCentralConfiguration(const std::string &C, std::vector<std::string> &Error, bool strict) { return ConfigurationValidator::instance()->Validate(C, Error, strict); }
} }