mirror of https://github.com/Icinga/icinga2.git
parent
d24af1e639
commit
425a1a0166
|
@ -172,6 +172,8 @@ int ApiSetupUtility::SetupMasterApiUser(const String& cn)
|
||||||
<< "object ApiUser \"" << api_username << "\" {\n"
|
<< "object ApiUser \"" << api_username << "\" {\n"
|
||||||
<< " password = \"" << api_password << "\"\n"
|
<< " password = \"" << api_password << "\"\n"
|
||||||
<< " //client_cn = \"\"\n"
|
<< " //client_cn = \"\"\n"
|
||||||
|
<< "\n"
|
||||||
|
<< " permissions = [ \"*\" ]\n"
|
||||||
<< "}\n";
|
<< "}\n";
|
||||||
|
|
||||||
fp.close();
|
fp.close();
|
||||||
|
|
|
@ -59,19 +59,24 @@ bool ActionsHandler::HandleRequest(const ApiUser::Ptr& user, HttpRequest& reques
|
||||||
const std::vector<String>& types = action->GetTypes();
|
const std::vector<String>& types = action->GetTypes();
|
||||||
std::vector<Value> objs;
|
std::vector<Value> objs;
|
||||||
|
|
||||||
|
String permission = "actions/" + actionName;
|
||||||
|
|
||||||
if (!types.empty()) {
|
if (!types.empty()) {
|
||||||
qd.Types = std::set<String>(types.begin(), types.end());
|
qd.Types = std::set<String>(types.begin(), types.end());
|
||||||
|
qd.Permission = permission;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
objs = FilterUtility::GetFilterTargets(qd, params);
|
objs = FilterUtility::GetFilterTargets(qd, params, user);
|
||||||
} catch (const std::exception& ex) {
|
} catch (const std::exception& ex) {
|
||||||
HttpUtility::SendJsonError(response, 400,
|
HttpUtility::SendJsonError(response, 400,
|
||||||
"Type/Filter was required but not provided or was invalid.",
|
"Type/Filter was required but not provided or was invalid.",
|
||||||
request.GetVerboseErrors() ? DiagnosticInformation(ex) : "");
|
request.GetVerboseErrors() ? DiagnosticInformation(ex) : "");
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
} else
|
} else {
|
||||||
|
FilterUtility::CheckPermission(user, permission);
|
||||||
objs.push_back(ConfigObject::Ptr());
|
objs.push_back(ConfigObject::Ptr());
|
||||||
|
}
|
||||||
|
|
||||||
Array::Ptr results = new Array();
|
Array::Ptr results = new Array();
|
||||||
|
|
||||||
|
|
|
@ -25,21 +25,6 @@ using namespace icinga;
|
||||||
|
|
||||||
REGISTER_TYPE(ApiUser);
|
REGISTER_TYPE(ApiUser);
|
||||||
|
|
||||||
String ApiUser::GetPassword(void) const
|
|
||||||
{
|
|
||||||
return "*****";
|
|
||||||
}
|
|
||||||
|
|
||||||
void ApiUser::SetPassword(const String& password)
|
|
||||||
{
|
|
||||||
SetPasswordRaw(password);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ApiUser::CheckPassword(const String& password) const
|
|
||||||
{
|
|
||||||
return password == GetPasswordRaw();
|
|
||||||
}
|
|
||||||
|
|
||||||
ApiUser::Ptr ApiUser::GetByClientCN(const String& cn)
|
ApiUser::Ptr ApiUser::GetByClientCN(const String& cn)
|
||||||
{
|
{
|
||||||
BOOST_FOREACH(const ApiUser::Ptr& user, ConfigType::GetObjectsByType<ApiUser>()) {
|
BOOST_FOREACH(const ApiUser::Ptr& user, ConfigType::GetObjectsByType<ApiUser>()) {
|
||||||
|
|
|
@ -35,10 +35,6 @@ public:
|
||||||
DECLARE_OBJECT(ApiUser);
|
DECLARE_OBJECT(ApiUser);
|
||||||
DECLARE_OBJECTNAME(ApiUser);
|
DECLARE_OBJECTNAME(ApiUser);
|
||||||
|
|
||||||
String GetPassword(void) const;
|
|
||||||
void SetPassword(const String& password);
|
|
||||||
bool CheckPassword(const String& password) const;
|
|
||||||
|
|
||||||
static ApiUser::Ptr GetByClientCN(const String& cn);
|
static ApiUser::Ptr GetByClientCN(const String& cn);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -18,6 +18,7 @@
|
||||||
******************************************************************************/
|
******************************************************************************/
|
||||||
|
|
||||||
#include "base/configobject.hpp"
|
#include "base/configobject.hpp"
|
||||||
|
#include "base/function.hpp"
|
||||||
|
|
||||||
library remote;
|
library remote;
|
||||||
|
|
||||||
|
@ -26,8 +27,20 @@ namespace icinga
|
||||||
|
|
||||||
class ApiUser : ConfigObject
|
class ApiUser : ConfigObject
|
||||||
{
|
{
|
||||||
[config, protected] String password (PasswordRaw);
|
[config] String password;
|
||||||
[config] String client_cn (ClientCN);
|
[config] String client_cn (ClientCN);
|
||||||
|
[config] array(Value) permissions;
|
||||||
|
};
|
||||||
|
|
||||||
|
validator ApiUser {
|
||||||
|
Array permissions {
|
||||||
|
String "*";
|
||||||
|
Dictionary "*" {
|
||||||
|
required permission;
|
||||||
|
String permission;
|
||||||
|
Function filter;
|
||||||
|
};
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,6 +20,7 @@
|
||||||
#include "remote/configfileshandler.hpp"
|
#include "remote/configfileshandler.hpp"
|
||||||
#include "remote/configpackageutility.hpp"
|
#include "remote/configpackageutility.hpp"
|
||||||
#include "remote/httputility.hpp"
|
#include "remote/httputility.hpp"
|
||||||
|
#include "remote/filterutility.hpp"
|
||||||
#include "base/exception.hpp"
|
#include "base/exception.hpp"
|
||||||
#include <boost/algorithm/string/join.hpp>
|
#include <boost/algorithm/string/join.hpp>
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
|
@ -55,6 +56,8 @@ void ConfigFilesHandler::HandleGet(const ApiUser::Ptr& user, HttpRequest& reques
|
||||||
params->Set("path", boost::algorithm::join(tmpPath, "/"));
|
params->Set("path", boost::algorithm::join(tmpPath, "/"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
FilterUtility::CheckPermission(user, "config/query");
|
||||||
|
|
||||||
String packageName = HttpUtility::GetLastParameter(params, "package");
|
String packageName = HttpUtility::GetLastParameter(params, "package");
|
||||||
String stageName = HttpUtility::GetLastParameter(params, "stage");
|
String stageName = HttpUtility::GetLastParameter(params, "stage");
|
||||||
|
|
||||||
|
|
|
@ -20,6 +20,7 @@
|
||||||
#include "remote/configpackageshandler.hpp"
|
#include "remote/configpackageshandler.hpp"
|
||||||
#include "remote/configpackageutility.hpp"
|
#include "remote/configpackageutility.hpp"
|
||||||
#include "remote/httputility.hpp"
|
#include "remote/httputility.hpp"
|
||||||
|
#include "remote/filterutility.hpp"
|
||||||
#include "base/exception.hpp"
|
#include "base/exception.hpp"
|
||||||
#include <boost/algorithm/string/join.hpp>
|
#include <boost/algorithm/string/join.hpp>
|
||||||
|
|
||||||
|
@ -49,6 +50,8 @@ bool ConfigPackagesHandler::HandleRequest(const ApiUser::Ptr& user, HttpRequest&
|
||||||
|
|
||||||
void ConfigPackagesHandler::HandleGet(const ApiUser::Ptr& user, HttpRequest& request, HttpResponse& response)
|
void ConfigPackagesHandler::HandleGet(const ApiUser::Ptr& user, HttpRequest& request, HttpResponse& response)
|
||||||
{
|
{
|
||||||
|
FilterUtility::CheckPermission(user, "config/query");
|
||||||
|
|
||||||
std::vector<String> packages = ConfigPackageUtility::GetPackages();
|
std::vector<String> packages = ConfigPackageUtility::GetPackages();
|
||||||
|
|
||||||
Array::Ptr results = new Array();
|
Array::Ptr results = new Array();
|
||||||
|
@ -70,6 +73,8 @@ void ConfigPackagesHandler::HandleGet(const ApiUser::Ptr& user, HttpRequest& req
|
||||||
|
|
||||||
void ConfigPackagesHandler::HandlePost(const ApiUser::Ptr& user, HttpRequest& request, HttpResponse& response)
|
void ConfigPackagesHandler::HandlePost(const ApiUser::Ptr& user, HttpRequest& request, HttpResponse& response)
|
||||||
{
|
{
|
||||||
|
FilterUtility::CheckPermission(user, "config/modify");
|
||||||
|
|
||||||
Dictionary::Ptr params = HttpUtility::FetchRequestParameters(request);
|
Dictionary::Ptr params = HttpUtility::FetchRequestParameters(request);
|
||||||
|
|
||||||
if (request.RequestUrl->GetPath().size() >= 4)
|
if (request.RequestUrl->GetPath().size() >= 4)
|
||||||
|
@ -106,6 +111,8 @@ void ConfigPackagesHandler::HandlePost(const ApiUser::Ptr& user, HttpRequest& re
|
||||||
|
|
||||||
void ConfigPackagesHandler::HandleDelete(const ApiUser::Ptr& user, HttpRequest& request, HttpResponse& response)
|
void ConfigPackagesHandler::HandleDelete(const ApiUser::Ptr& user, HttpRequest& request, HttpResponse& response)
|
||||||
{
|
{
|
||||||
|
FilterUtility::CheckPermission(user, "config/modify");
|
||||||
|
|
||||||
Dictionary::Ptr params = HttpUtility::FetchRequestParameters(request);
|
Dictionary::Ptr params = HttpUtility::FetchRequestParameters(request);
|
||||||
|
|
||||||
if (request.RequestUrl->GetPath().size() >= 4)
|
if (request.RequestUrl->GetPath().size() >= 4)
|
||||||
|
|
|
@ -20,6 +20,7 @@
|
||||||
#include "remote/configstageshandler.hpp"
|
#include "remote/configstageshandler.hpp"
|
||||||
#include "remote/configpackageutility.hpp"
|
#include "remote/configpackageutility.hpp"
|
||||||
#include "remote/httputility.hpp"
|
#include "remote/httputility.hpp"
|
||||||
|
#include "remote/filterutility.hpp"
|
||||||
#include "base/application.hpp"
|
#include "base/application.hpp"
|
||||||
#include "base/exception.hpp"
|
#include "base/exception.hpp"
|
||||||
#include <boost/foreach.hpp>
|
#include <boost/foreach.hpp>
|
||||||
|
@ -51,6 +52,8 @@ bool ConfigStagesHandler::HandleRequest(const ApiUser::Ptr& user, HttpRequest& r
|
||||||
|
|
||||||
void ConfigStagesHandler::HandleGet(const ApiUser::Ptr& user, HttpRequest& request, HttpResponse& response)
|
void ConfigStagesHandler::HandleGet(const ApiUser::Ptr& user, HttpRequest& request, HttpResponse& response)
|
||||||
{
|
{
|
||||||
|
FilterUtility::CheckPermission(user, "config/query");
|
||||||
|
|
||||||
Dictionary::Ptr params = HttpUtility::FetchRequestParameters(request);
|
Dictionary::Ptr params = HttpUtility::FetchRequestParameters(request);
|
||||||
|
|
||||||
if (request.RequestUrl->GetPath().size() >= 4)
|
if (request.RequestUrl->GetPath().size() >= 4)
|
||||||
|
@ -91,6 +94,8 @@ void ConfigStagesHandler::HandleGet(const ApiUser::Ptr& user, HttpRequest& reque
|
||||||
|
|
||||||
void ConfigStagesHandler::HandlePost(const ApiUser::Ptr& user, HttpRequest& request, HttpResponse& response)
|
void ConfigStagesHandler::HandlePost(const ApiUser::Ptr& user, HttpRequest& request, HttpResponse& response)
|
||||||
{
|
{
|
||||||
|
FilterUtility::CheckPermission(user, "config/modify");
|
||||||
|
|
||||||
Dictionary::Ptr params = HttpUtility::FetchRequestParameters(request);
|
Dictionary::Ptr params = HttpUtility::FetchRequestParameters(request);
|
||||||
|
|
||||||
if (request.RequestUrl->GetPath().size() >= 4)
|
if (request.RequestUrl->GetPath().size() >= 4)
|
||||||
|
@ -136,6 +141,8 @@ void ConfigStagesHandler::HandlePost(const ApiUser::Ptr& user, HttpRequest& requ
|
||||||
|
|
||||||
void ConfigStagesHandler::HandleDelete(const ApiUser::Ptr& user, HttpRequest& request, HttpResponse& response)
|
void ConfigStagesHandler::HandleDelete(const ApiUser::Ptr& user, HttpRequest& request, HttpResponse& response)
|
||||||
{
|
{
|
||||||
|
FilterUtility::CheckPermission(user, "config/modify");
|
||||||
|
|
||||||
Dictionary::Ptr params = HttpUtility::FetchRequestParameters(request);
|
Dictionary::Ptr params = HttpUtility::FetchRequestParameters(request);
|
||||||
|
|
||||||
if (request.RequestUrl->GetPath().size() >= 4)
|
if (request.RequestUrl->GetPath().size() >= 4)
|
||||||
|
|
|
@ -48,6 +48,8 @@ bool CreateObjectHandler::HandleRequest(const ApiUser::Ptr& user, HttpRequest& r
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
FilterUtility::CheckPermission(user, "objects/create/" + type->GetName());
|
||||||
|
|
||||||
String name = request.RequestUrl->GetPath()[3];
|
String name = request.RequestUrl->GetPath()[3];
|
||||||
Dictionary::Ptr params = HttpUtility::FetchRequestParameters(request);
|
Dictionary::Ptr params = HttpUtility::FetchRequestParameters(request);
|
||||||
Array::Ptr templates = params->Get("templates");
|
Array::Ptr templates = params->Get("templates");
|
||||||
|
|
|
@ -66,7 +66,7 @@ bool DeleteObjectHandler::HandleRequest(const ApiUser::Ptr& user, HttpRequest& r
|
||||||
params->Set(attr, request.RequestUrl->GetPath()[3]);
|
params->Set(attr, request.RequestUrl->GetPath()[3]);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<Value> objs = FilterUtility::GetFilterTargets(qd, params);
|
std::vector<Value> objs = FilterUtility::GetFilterTargets(qd, params, user);
|
||||||
|
|
||||||
bool cascade = HttpUtility::GetLastParameter(params, "cascade");
|
bool cascade = HttpUtility::GetLastParameter(params, "cascade");
|
||||||
|
|
||||||
|
|
|
@ -78,13 +78,23 @@ String ConfigObjectTargetProvider::GetPluralName(const String& type) const
|
||||||
return Type::GetByName(type)->GetPluralName();
|
return Type::GetByName(type)->GetPluralName();
|
||||||
}
|
}
|
||||||
|
|
||||||
static void FilteredAddTarget(ScriptFrame& frame, Expression *ufilter, std::vector<Value>& result, const Object::Ptr& target)
|
static bool EvaluateFilter(ScriptFrame& frame, Expression *filter, const Object::Ptr& target)
|
||||||
{
|
{
|
||||||
Type::Ptr type = target->GetReflectionType();
|
if (!filter)
|
||||||
String varName = type->GetName();
|
return true;
|
||||||
boost::algorithm::to_lower(varName);
|
|
||||||
|
|
||||||
frame.Locals->Set(varName, target);
|
Type::Ptr type = target->GetReflectionType();
|
||||||
|
String varName = type->GetName().ToLower();
|
||||||
|
|
||||||
|
Dictionary::Ptr vars;
|
||||||
|
|
||||||
|
if (frame.Self.IsEmpty()) {
|
||||||
|
vars = new Dictionary();
|
||||||
|
frame.Self = vars;
|
||||||
|
} else
|
||||||
|
vars = frame.Self;
|
||||||
|
|
||||||
|
vars->Set(varName, target);
|
||||||
|
|
||||||
for (int fid = 0; fid < type->GetFieldCount(); fid++) {
|
for (int fid = 0; fid < type->GetFieldCount(); fid++) {
|
||||||
Field field = type->GetFieldInfo(fid);
|
Field field = type->GetFieldInfo(fid);
|
||||||
|
@ -97,14 +107,68 @@ static void FilteredAddTarget(ScriptFrame& frame, Expression *ufilter, std::vect
|
||||||
varName = field.TypeName;
|
varName = field.TypeName;
|
||||||
boost::algorithm::to_lower(varName);
|
boost::algorithm::to_lower(varName);
|
||||||
|
|
||||||
frame.Locals->Set(varName, joinedObj);
|
vars->Set(varName, joinedObj);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Convert::ToBool(ufilter->Evaluate(frame)))
|
return Convert::ToBool(filter->Evaluate(frame));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void FilteredAddTarget(ScriptFrame& permissionFrame, Expression *permissionFilter,
|
||||||
|
ScriptFrame& frame, Expression *ufilter, std::vector<Value>& result, const Object::Ptr& target)
|
||||||
|
{
|
||||||
|
if (EvaluateFilter(permissionFrame, permissionFilter, target) && EvaluateFilter(frame, ufilter, target))
|
||||||
result.push_back(target);
|
result.push_back(target);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<Value> FilterUtility::GetFilterTargets(const QueryDescription& qd, const Dictionary::Ptr& query)
|
void FilterUtility::CheckPermission(const ApiUser::Ptr& user, const String& permission, Expression **permissionFilter)
|
||||||
|
{
|
||||||
|
if (permissionFilter)
|
||||||
|
*permissionFilter = NULL;
|
||||||
|
|
||||||
|
if (permission.IsEmpty())
|
||||||
|
return;
|
||||||
|
|
||||||
|
bool foundPermission = false;
|
||||||
|
String requiredPermission = permission.ToLower();
|
||||||
|
|
||||||
|
Array::Ptr permissions = user->GetPermissions();
|
||||||
|
if (permissions) {
|
||||||
|
ObjectLock olock(permissions);
|
||||||
|
BOOST_FOREACH(const Value& item, permissions) {
|
||||||
|
String permission;
|
||||||
|
Function::Ptr filter;
|
||||||
|
if (item.IsObjectType<Dictionary>()) {
|
||||||
|
Dictionary::Ptr dict = item;
|
||||||
|
permission = dict->Get("permission");
|
||||||
|
filter = dict->Get("filter");
|
||||||
|
} else
|
||||||
|
permission = item;
|
||||||
|
|
||||||
|
permission = permission.ToLower();
|
||||||
|
|
||||||
|
if (!Utility::Match(permission, requiredPermission))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
foundPermission = true;
|
||||||
|
|
||||||
|
if (filter && permissionFilter) {
|
||||||
|
std::vector<Expression *> args;
|
||||||
|
args.push_back(new GetScopeExpression(ScopeLocal));
|
||||||
|
FunctionCallExpression *fexpr = new FunctionCallExpression(new IndexerExpression(MakeLiteral(filter), MakeLiteral("call")), args);
|
||||||
|
|
||||||
|
if (!*permissionFilter)
|
||||||
|
*permissionFilter = fexpr;
|
||||||
|
else
|
||||||
|
*permissionFilter = new LogicalOrExpression(*permissionFilter, fexpr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!foundPermission)
|
||||||
|
BOOST_THROW_EXCEPTION(ScriptError("Missing permission: " + requiredPermission));
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<Value> FilterUtility::GetFilterTargets(const QueryDescription& qd, const Dictionary::Ptr& query, const ApiUser::Ptr& user)
|
||||||
{
|
{
|
||||||
std::vector<Value> result;
|
std::vector<Value> result;
|
||||||
|
|
||||||
|
@ -115,6 +179,11 @@ std::vector<Value> FilterUtility::GetFilterTargets(const QueryDescription& qd, c
|
||||||
else
|
else
|
||||||
provider = new ConfigObjectTargetProvider();
|
provider = new ConfigObjectTargetProvider();
|
||||||
|
|
||||||
|
Expression *permissionFilter;
|
||||||
|
CheckPermission(user, qd.Permission, &permissionFilter);
|
||||||
|
|
||||||
|
ScriptFrame permissionFrame;
|
||||||
|
|
||||||
BOOST_FOREACH(const String& type, qd.Types) {
|
BOOST_FOREACH(const String& type, qd.Types) {
|
||||||
String attr = type;
|
String attr = type;
|
||||||
boost::algorithm::to_lower(attr);
|
boost::algorithm::to_lower(attr);
|
||||||
|
@ -122,8 +191,12 @@ std::vector<Value> FilterUtility::GetFilterTargets(const QueryDescription& qd, c
|
||||||
if (attr == "type")
|
if (attr == "type")
|
||||||
attr = "name";
|
attr = "name";
|
||||||
|
|
||||||
if (query->Contains(attr))
|
if (query->Contains(attr)) {
|
||||||
result.push_back(provider->GetTargetByName(type, HttpUtility::GetLastParameter(query, attr)));
|
Object::Ptr target = provider->GetTargetByName(type, HttpUtility::GetLastParameter(query, attr));
|
||||||
|
|
||||||
|
if (EvaluateFilter(permissionFrame, permissionFilter, target))
|
||||||
|
result.push_back(target);
|
||||||
|
}
|
||||||
|
|
||||||
attr = provider->GetPluralName(type);
|
attr = provider->GetPluralName(type);
|
||||||
boost::algorithm::to_lower(attr);
|
boost::algorithm::to_lower(attr);
|
||||||
|
@ -133,7 +206,10 @@ std::vector<Value> FilterUtility::GetFilterTargets(const QueryDescription& qd, c
|
||||||
if (names) {
|
if (names) {
|
||||||
ObjectLock olock(names);
|
ObjectLock olock(names);
|
||||||
BOOST_FOREACH(const String& name, names) {
|
BOOST_FOREACH(const String& name, names) {
|
||||||
result.push_back(provider->GetTargetByName(type, name));
|
Object::Ptr target = provider->GetTargetByName(type, name);
|
||||||
|
|
||||||
|
if (EvaluateFilter(permissionFrame, permissionFilter, target))
|
||||||
|
result.push_back(target);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -159,20 +235,26 @@ std::vector<Value> FilterUtility::GetFilterTargets(const QueryDescription& qd, c
|
||||||
if (qd.Types.find(type) == qd.Types.end())
|
if (qd.Types.find(type) == qd.Types.end())
|
||||||
BOOST_THROW_EXCEPTION(std::invalid_argument("Invalid type specified for this query."));
|
BOOST_THROW_EXCEPTION(std::invalid_argument("Invalid type specified for this query."));
|
||||||
|
|
||||||
Expression *ufilter = ConfigCompiler::CompileText("<API query>", filter);
|
|
||||||
ScriptFrame frame;
|
ScriptFrame frame;
|
||||||
frame.Sandboxed = true;
|
frame.Sandboxed = true;
|
||||||
|
Dictionary::Ptr uvars = new Dictionary();
|
||||||
|
|
||||||
|
Expression *ufilter = ConfigCompiler::CompileText("<API query>", filter);
|
||||||
|
|
||||||
Dictionary::Ptr filter_vars = query->Get("filter_vars");
|
Dictionary::Ptr filter_vars = query->Get("filter_vars");
|
||||||
if (filter_vars) {
|
if (filter_vars) {
|
||||||
ObjectLock olock(filter_vars);
|
ObjectLock olock(filter_vars);
|
||||||
BOOST_FOREACH(const Dictionary::Pair& kv, filter_vars) {
|
BOOST_FOREACH(const Dictionary::Pair& kv, filter_vars) {
|
||||||
frame.Locals->Set(kv.first, kv.second);
|
uvars->Set(kv.first, kv.second);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
frame.Self = uvars;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
provider->FindTargets(type, boost::bind(&FilteredAddTarget, boost::ref(frame), ufilter, boost::ref(result), _1));
|
provider->FindTargets(type, boost::bind(&FilteredAddTarget,
|
||||||
|
boost::ref(permissionFrame), permissionFilter,
|
||||||
|
boost::ref(frame), ufilter, boost::ref(result), _1));
|
||||||
} catch (const std::exception& ex) {
|
} catch (const std::exception& ex) {
|
||||||
delete ufilter;
|
delete ufilter;
|
||||||
throw;
|
throw;
|
||||||
|
|
|
@ -21,6 +21,8 @@
|
||||||
#define FILTERUTILITY_H
|
#define FILTERUTILITY_H
|
||||||
|
|
||||||
#include "remote/i2-remote.hpp"
|
#include "remote/i2-remote.hpp"
|
||||||
|
#include "remote/apiuser.hpp"
|
||||||
|
#include "config/expression.hpp"
|
||||||
#include "base/dictionary.hpp"
|
#include "base/dictionary.hpp"
|
||||||
#include "base/configobject.hpp"
|
#include "base/configobject.hpp"
|
||||||
#include <set>
|
#include <set>
|
||||||
|
@ -54,6 +56,7 @@ struct QueryDescription
|
||||||
{
|
{
|
||||||
std::set<String> Types;
|
std::set<String> Types;
|
||||||
TargetProvider::Ptr Provider;
|
TargetProvider::Ptr Provider;
|
||||||
|
String Permission;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -65,7 +68,8 @@ class I2_REMOTE_API FilterUtility
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
static Type::Ptr TypeFromPluralName(const String& pluralName);
|
static Type::Ptr TypeFromPluralName(const String& pluralName);
|
||||||
static std::vector<Value> GetFilterTargets(const QueryDescription& qd, const Dictionary::Ptr& query);
|
static void CheckPermission(const ApiUser::Ptr& user, const String& permission, Expression **filter = NULL);
|
||||||
|
static std::vector<Value> GetFilterTargets(const QueryDescription& qd, const Dictionary::Ptr& query, const ApiUser::Ptr& user);
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -141,7 +141,7 @@ void HttpServerConnection::ProcessMessageAsync(HttpRequest& request)
|
||||||
else {
|
else {
|
||||||
user = ApiUser::GetByName(username);
|
user = ApiUser::GetByName(username);
|
||||||
|
|
||||||
if (!user || !user->CheckPassword(password))
|
if (user && user->GetPassword() != password)
|
||||||
user.reset();
|
user.reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -59,7 +59,7 @@ bool ModifyObjectHandler::HandleRequest(const ApiUser::Ptr& user, HttpRequest& r
|
||||||
params->Set(attr, request.RequestUrl->GetPath()[3]);
|
params->Set(attr, request.RequestUrl->GetPath()[3]);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<Value> objs = FilterUtility::GetFilterTargets(qd, params);
|
std::vector<Value> objs = FilterUtility::GetFilterTargets(qd, params, user);
|
||||||
|
|
||||||
Dictionary::Ptr attrs = params->Get("attrs");
|
Dictionary::Ptr attrs = params->Get("attrs");
|
||||||
|
|
||||||
|
|
|
@ -45,6 +45,7 @@ bool ObjectQueryHandler::HandleRequest(const ApiUser::Ptr& user, HttpRequest& re
|
||||||
|
|
||||||
QueryDescription qd;
|
QueryDescription qd;
|
||||||
qd.Types.insert(type->GetName());
|
qd.Types.insert(type->GetName());
|
||||||
|
qd.Permission = "objects/query/" + type->GetName();
|
||||||
|
|
||||||
std::vector<String> joinAttrs;
|
std::vector<String> joinAttrs;
|
||||||
joinAttrs.push_back("");
|
joinAttrs.push_back("");
|
||||||
|
@ -66,7 +67,7 @@ bool ObjectQueryHandler::HandleRequest(const ApiUser::Ptr& user, HttpRequest& re
|
||||||
params->Set(attr, request.RequestUrl->GetPath()[3]);
|
params->Set(attr, request.RequestUrl->GetPath()[3]);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<Value> objs = FilterUtility::GetFilterTargets(qd, params);
|
std::vector<Value> objs = FilterUtility::GetFilterTargets(qd, params, user);
|
||||||
|
|
||||||
Array::Ptr results = new Array();
|
Array::Ptr results = new Array();
|
||||||
|
|
||||||
|
|
|
@ -19,6 +19,7 @@
|
||||||
|
|
||||||
#include "remote/statushandler.hpp"
|
#include "remote/statushandler.hpp"
|
||||||
#include "remote/httputility.hpp"
|
#include "remote/httputility.hpp"
|
||||||
|
#include "remote/filterutility.hpp"
|
||||||
#include "base/serializer.hpp"
|
#include "base/serializer.hpp"
|
||||||
#include "base/statsfunction.hpp"
|
#include "base/statsfunction.hpp"
|
||||||
|
|
||||||
|
@ -26,6 +27,48 @@ using namespace icinga;
|
||||||
|
|
||||||
REGISTER_URLHANDLER("/v1/status", StatusHandler);
|
REGISTER_URLHANDLER("/v1/status", StatusHandler);
|
||||||
|
|
||||||
|
class StatusTargetProvider : public TargetProvider
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
DECLARE_PTR_TYPEDEFS(StatusTargetProvider);
|
||||||
|
|
||||||
|
virtual void FindTargets(const String& type,
|
||||||
|
const boost::function<void (const Value&)>& addTarget) const override
|
||||||
|
{
|
||||||
|
typedef std::pair<String, StatsFunction::Ptr> kv_pair;
|
||||||
|
BOOST_FOREACH(const kv_pair& kv, StatsFunctionRegistry::GetInstance()->GetItems()) {
|
||||||
|
addTarget(GetTargetByName("Status", kv.first));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual Value GetTargetByName(const String& type, const String& name) const override
|
||||||
|
{
|
||||||
|
StatsFunction::Ptr func = StatsFunctionRegistry::GetInstance()->GetItem(name);
|
||||||
|
|
||||||
|
Dictionary::Ptr result = new Dictionary();
|
||||||
|
|
||||||
|
Dictionary::Ptr status = new Dictionary();
|
||||||
|
Array::Ptr perfdata = new Array();
|
||||||
|
func->Invoke(status, perfdata);
|
||||||
|
|
||||||
|
result->Set("name", name);
|
||||||
|
result->Set("status", status);
|
||||||
|
result->Set("perfdata", perfdata);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual bool IsValidType(const String& type) const override
|
||||||
|
{
|
||||||
|
return type == "Status";
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual String GetPluralName(const String& type) const override
|
||||||
|
{
|
||||||
|
return "statuses";
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
bool StatusHandler::HandleRequest(const ApiUser::Ptr& user, HttpRequest& request, HttpResponse& response)
|
bool StatusHandler::HandleRequest(const ApiUser::Ptr& user, HttpRequest& request, HttpResponse& response)
|
||||||
{
|
{
|
||||||
Dictionary::Ptr result = new Dictionary();
|
Dictionary::Ptr result = new Dictionary();
|
||||||
|
@ -37,46 +80,22 @@ bool StatusHandler::HandleRequest(const ApiUser::Ptr& user, HttpRequest& request
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (request.RequestUrl->GetPath().size() < 2) {
|
|
||||||
response.SetStatus(400, "Bad request");
|
|
||||||
HttpUtility::SendJsonBody(response, result);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
Array::Ptr results = new Array();
|
QueryDescription qd;
|
||||||
Dictionary::Ptr resultInner = new Dictionary();
|
qd.Types.insert("Status");
|
||||||
|
qd.Provider = new StatusTargetProvider();
|
||||||
|
qd.Permission = "status/query";
|
||||||
|
|
||||||
if (request.RequestUrl->GetPath().size() > 2) {
|
Dictionary::Ptr params = HttpUtility::FetchRequestParameters(request);
|
||||||
|
|
||||||
StatsFunction::Ptr funcptr = StatsFunctionRegistry::GetInstance()->GetItem(request.RequestUrl->GetPath()[2]);
|
params->Set("type", "Status");
|
||||||
resultInner = new Dictionary();
|
|
||||||
|
|
||||||
if (!funcptr)
|
if (request.RequestUrl->GetPath().size() >= 3)
|
||||||
return false;
|
params->Set("name", request.RequestUrl->GetPath()[2]);
|
||||||
|
|
||||||
results->Add(resultInner);
|
std::vector<Value> objs = FilterUtility::GetFilterTargets(qd, params, user);
|
||||||
|
|
||||||
Dictionary::Ptr status = new Dictionary();
|
Array::Ptr results = Array::FromVector(objs);
|
||||||
Array::Ptr perfdata = new Array();
|
|
||||||
funcptr->Invoke(status, perfdata);
|
|
||||||
|
|
||||||
resultInner->Set("status", status);
|
|
||||||
resultInner->Set("perfdata", perfdata);
|
|
||||||
} else {
|
|
||||||
typedef std::pair<String, StatsFunction::Ptr> kv_pair;
|
|
||||||
BOOST_FOREACH(const kv_pair& kv, StatsFunctionRegistry::GetInstance()->GetItems()) {
|
|
||||||
resultInner = new Dictionary();
|
|
||||||
Dictionary::Ptr funcStatus = new Dictionary();
|
|
||||||
Array::Ptr funcPData = new Array();
|
|
||||||
kv.second->Invoke(funcStatus, funcPData);
|
|
||||||
|
|
||||||
resultInner->Set("name", kv.first);
|
|
||||||
resultInner->Set("status", funcPData);
|
|
||||||
resultInner->Set("perfdata", funcPData);
|
|
||||||
|
|
||||||
results->Add(resultInner);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
result->Set("results", results);
|
result->Set("results", results);
|
||||||
|
|
||||||
|
|
|
@ -77,11 +77,14 @@ public:
|
||||||
|
|
||||||
bool TypeQueryHandler::HandleRequest(const ApiUser::Ptr& user, HttpRequest& request, HttpResponse& response)
|
bool TypeQueryHandler::HandleRequest(const ApiUser::Ptr& user, HttpRequest& request, HttpResponse& response)
|
||||||
{
|
{
|
||||||
if (request.RequestMethod != "GET")
|
Dictionary::Ptr result = new Dictionary();
|
||||||
return false;
|
|
||||||
|
|
||||||
if (request.RequestUrl->GetPath().size() < 2)
|
if (request.RequestMethod != "GET") {
|
||||||
return false;
|
response.SetStatus(400, "Bad request");
|
||||||
|
result->Set("info", "Request must be type GET");
|
||||||
|
HttpUtility::SendJsonBody(response, result);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
QueryDescription qd;
|
QueryDescription qd;
|
||||||
qd.Types.insert("Type");
|
qd.Types.insert("Type");
|
||||||
|
@ -97,7 +100,7 @@ bool TypeQueryHandler::HandleRequest(const ApiUser::Ptr& user, HttpRequest& requ
|
||||||
if (request.RequestUrl->GetPath().size() >= 3)
|
if (request.RequestUrl->GetPath().size() >= 3)
|
||||||
params->Set("name", request.RequestUrl->GetPath()[2]);
|
params->Set("name", request.RequestUrl->GetPath()[2]);
|
||||||
|
|
||||||
std::vector<Value> objs = FilterUtility::GetFilterTargets(qd, params);
|
std::vector<Value> objs = FilterUtility::GetFilterTargets(qd, params, user);
|
||||||
|
|
||||||
Array::Ptr results = new Array();
|
Array::Ptr results = new Array();
|
||||||
|
|
||||||
|
@ -154,7 +157,6 @@ bool TypeQueryHandler::HandleRequest(const ApiUser::Ptr& user, HttpRequest& requ
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Dictionary::Ptr result = new Dictionary();
|
|
||||||
result->Set("results", results);
|
result->Set("results", results);
|
||||||
|
|
||||||
response.SetStatus(200, "OK");
|
response.SetStatus(200, "OK");
|
||||||
|
|
|
@ -24,7 +24,7 @@ set(base_test_SOURCES
|
||||||
base-stream.cpp base-string.cpp base-timer.cpp base-type.cpp
|
base-stream.cpp base-string.cpp base-timer.cpp base-type.cpp
|
||||||
base-value.cpp config-ops.cpp icinga-macros.cpp
|
base-value.cpp config-ops.cpp icinga-macros.cpp
|
||||||
icinga-perfdata.cpp test.cpp
|
icinga-perfdata.cpp test.cpp
|
||||||
remote-url.cpp remote-apiuser.cpp
|
remote-url.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
set(livestatus_test_SOURCES
|
set(livestatus_test_SOURCES
|
||||||
|
@ -107,8 +107,6 @@ add_boost_test(base
|
||||||
icinga_perfdata/ignore_invalid_warn_crit_min_max
|
icinga_perfdata/ignore_invalid_warn_crit_min_max
|
||||||
icinga_perfdata/invalid
|
icinga_perfdata/invalid
|
||||||
icinga_perfdata/multi
|
icinga_perfdata/multi
|
||||||
remote_apiuser/get_password
|
|
||||||
remote_apiuser/check_password
|
|
||||||
remote_url/id_and_path
|
remote_url/id_and_path
|
||||||
remote_url/parameters
|
remote_url/parameters
|
||||||
remote_url/get_and_set
|
remote_url/get_and_set
|
||||||
|
|
|
@ -1,50 +0,0 @@
|
||||||
/******************************************************************************
|
|
||||||
* Icinga 2 *
|
|
||||||
* Copyright (C) 2012-2015 Icinga Development Team (http://www.icinga.org) *
|
|
||||||
* *
|
|
||||||
* This program is free software; you can redistribute it and/or *
|
|
||||||
* modify it under the terms of the GNU General Public License *
|
|
||||||
* as published by the Free Software Foundation; either version 2 *
|
|
||||||
* of the License, or (at your option) any later version. *
|
|
||||||
* *
|
|
||||||
* This program is distributed in the hope that it will be useful, *
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
|
||||||
* GNU General Public License for more details. *
|
|
||||||
* *
|
|
||||||
* You should have received a copy of the GNU General Public License *
|
|
||||||
* along with this program; if not, write to the Free Software Foundation *
|
|
||||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. *
|
|
||||||
******************************************************************************/
|
|
||||||
|
|
||||||
#include "remote/apiuser.hpp"
|
|
||||||
#include <boost/test/unit_test.hpp>
|
|
||||||
|
|
||||||
using namespace icinga;
|
|
||||||
|
|
||||||
BOOST_AUTO_TEST_SUITE(remote_apiuser)
|
|
||||||
|
|
||||||
BOOST_AUTO_TEST_CASE(construct)
|
|
||||||
{
|
|
||||||
ApiUser::Ptr apiuser = new ApiUser();
|
|
||||||
BOOST_CHECK(apiuser);
|
|
||||||
}
|
|
||||||
|
|
||||||
BOOST_AUTO_TEST_CASE(get_password)
|
|
||||||
{
|
|
||||||
ApiUser::Ptr apiuser = new ApiUser();
|
|
||||||
apiuser->SetPassword("icingar0xx");
|
|
||||||
|
|
||||||
BOOST_CHECK(apiuser->GetPassword() == "*****");
|
|
||||||
}
|
|
||||||
|
|
||||||
BOOST_AUTO_TEST_CASE(check_password)
|
|
||||||
{
|
|
||||||
ApiUser::Ptr apiuser = new ApiUser();
|
|
||||||
apiuser->SetPassword("icingar0xx");
|
|
||||||
|
|
||||||
BOOST_CHECK(apiuser->CheckPassword("1cing4r0xx") == false);
|
|
||||||
BOOST_CHECK(apiuser->CheckPassword("icingar0xx") == true);
|
|
||||||
}
|
|
||||||
|
|
||||||
BOOST_AUTO_TEST_SUITE_END()
|
|
|
@ -1089,10 +1089,11 @@ void ClassCompiler::CodeGenValidator(const std::string& name, const std::string&
|
||||||
else
|
else
|
||||||
m_Impl << "\t\t" << "const Dictionary::Ptr& dict = value;" << std::endl;
|
m_Impl << "\t\t" << "const Dictionary::Ptr& dict = value;" << std::endl;
|
||||||
|
|
||||||
m_Impl << (type_check ? "\t" : "") << "\t\t" << "ObjectLock olock(dict);" << std::endl
|
m_Impl << (type_check ? "\t" : "") << "\t\t" << "{" << std::endl
|
||||||
<< (type_check ? "\t" : "") << "\t\t" << "BOOST_FOREACH(const Dictionary::Pair& kv, dict) {" << std::endl
|
<< (type_check ? "\t" : "") << "\t\t\t" << "ObjectLock olock(dict);" << std::endl
|
||||||
<< (type_check ? "\t" : "") << "\t\t\t" << "const String& akey = kv.first;" << std::endl
|
<< (type_check ? "\t" : "") << "\t\t\t" << "BOOST_FOREACH(const Dictionary::Pair& kv, dict) {" << std::endl
|
||||||
<< (type_check ? "\t" : "") << "\t\t\t" << "const Value& avalue = kv.second;" << std::endl;
|
<< (type_check ? "\t" : "") << "\t\t\t\t" << "const String& akey = kv.first;" << std::endl
|
||||||
|
<< (type_check ? "\t" : "") << "\t\t\t\t" << "const Value& avalue = kv.second;" << std::endl;
|
||||||
indent = true;
|
indent = true;
|
||||||
} else if (rule.Type == "Array") {
|
} else if (rule.Type == "Array") {
|
||||||
if (type_check)
|
if (type_check)
|
||||||
|
@ -1101,9 +1102,10 @@ void ClassCompiler::CodeGenValidator(const std::string& name, const std::string&
|
||||||
m_Impl << "\t\t" << "const Array::Ptr& arr = value;" << std::endl;
|
m_Impl << "\t\t" << "const Array::Ptr& arr = value;" << std::endl;
|
||||||
|
|
||||||
m_Impl << (type_check ? "\t" : "") << "\t\t" << "Array::SizeType anum = 0;" << std::endl
|
m_Impl << (type_check ? "\t" : "") << "\t\t" << "Array::SizeType anum = 0;" << std::endl
|
||||||
<< (type_check ? "\t" : "") << "\t\t" << "ObjectLock olock(arr);" << std::endl
|
<< (type_check ? "\t" : "") << "\t\t" << "{" << std::endl
|
||||||
<< (type_check ? "\t" : "") << "\t\t" << "BOOST_FOREACH(const Value& avalue, arr) {" << std::endl
|
<< (type_check ? "\t" : "") << "\t\t\t" << "ObjectLock olock(arr);" << std::endl
|
||||||
<< (type_check ? "\t" : "") << "\t\t\t" << "String akey = Convert::ToString(anum);" << std::endl;
|
<< (type_check ? "\t" : "") << "\t\t\t" << "BOOST_FOREACH(const Value& avalue, arr) {" << std::endl
|
||||||
|
<< (type_check ? "\t" : "") << "\t\t\t\t" << "String akey = Convert::ToString(anum);" << std::endl;
|
||||||
indent = true;
|
indent = true;
|
||||||
} else {
|
} else {
|
||||||
m_Impl << (type_check ? "\t" : "") << "\t\t" << "String akey = \"\";" << std::endl
|
m_Impl << (type_check ? "\t" : "") << "\t\t" << "String akey = \"\";" << std::endl
|
||||||
|
@ -1117,15 +1119,17 @@ void ClassCompiler::CodeGenValidator(const std::string& name, const std::string&
|
||||||
else
|
else
|
||||||
subvalidator_prefix = name;
|
subvalidator_prefix = name;
|
||||||
|
|
||||||
m_Impl << (type_check ? "\t" : "") << (indent ? "\t" : "") << "\t\t" << "location.push_back(akey);" << std::endl
|
m_Impl << (type_check ? "\t" : "") << (indent ? "\t\t" : "") << "\t\t" << "location.push_back(akey);" << std::endl
|
||||||
<< (type_check ? "\t" : "") << (indent ? "\t" : "") << "\t\t" << "TIValidate" << subvalidator_prefix << "_" << i << "(object, akey, avalue, location, utils);" << std::endl
|
<< (type_check ? "\t" : "") << (indent ? "\t\t" : "") << "\t\t" << "TIValidate" << subvalidator_prefix << "_" << i << "(object, akey, avalue, location, utils);" << std::endl
|
||||||
<< (type_check ? "\t" : "") << (indent ? "\t" : "") << "\t\t" << "location.pop_back();" << std::endl;
|
<< (type_check ? "\t" : "") << (indent ? "\t\t" : "") << "\t\t" << "location.pop_back();" << std::endl;
|
||||||
|
|
||||||
if (rule.Type == "Array")
|
if (rule.Type == "Array")
|
||||||
m_Impl << (type_check ? "\t" : "") << "\t\t\t" << "anum++;" << std::endl;
|
m_Impl << (type_check ? "\t" : "") << "\t\t\t\t" << "anum++;" << std::endl;
|
||||||
|
|
||||||
if (rule.Type == "Dictionary" || rule.Type == "Array")
|
if (rule.Type == "Dictionary" || rule.Type == "Array") {
|
||||||
m_Impl << (type_check ? "\t" : "") << "\t\t" << "}" << std::endl;
|
m_Impl << (type_check ? "\t" : "") << "\t\t\t" << "}" << std::endl
|
||||||
|
<< (type_check ? "\t" : "") << "\t\t" << "}" << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
for (std::vector<Rule>::size_type i = 0; i < rule.Rules.size(); i++) {
|
for (std::vector<Rule>::size_type i = 0; i < rule.Rules.size(); i++) {
|
||||||
const Rule& srule = rule.Rules[i];
|
const Rule& srule = rule.Rules[i];
|
||||||
|
@ -1134,8 +1138,8 @@ void ClassCompiler::CodeGenValidator(const std::string& name, const std::string&
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (rule.Type == "Dictionary") {
|
if (rule.Type == "Dictionary") {
|
||||||
m_Impl << (type_check ? "\t" : "") << "\t\t" << "if (dict.Get(\"" << srule.Pattern << "\").IsEmpty())" << std::endl
|
m_Impl << (type_check ? "\t" : "") << "\t\t" << "if (dict->Get(\"" << srule.Pattern << "\").IsEmpty())" << std::endl
|
||||||
<< (type_check ? "\t" : "") << "\t\t\t" << "BOOST_THROW_EXCEPTION(ValidationError(dynamic_cast<ConfigObject *>(this), location, \"Required dictionary item '" << srule.Pattern << "' is not set.\"));" << std::endl;
|
<< (type_check ? "\t" : "") << "\t\t\t" << "BOOST_THROW_EXCEPTION(ValidationError(dynamic_pointer_cast<ConfigObject>(object), location, \"Required dictionary item '" << srule.Pattern << "' is not set.\"));" << std::endl;
|
||||||
} else if (rule.Type == "Array") {
|
} else if (rule.Type == "Array") {
|
||||||
int index = -1;
|
int index = -1;
|
||||||
std::stringstream idxbuf;
|
std::stringstream idxbuf;
|
||||||
|
|
Loading…
Reference in New Issue