diff --git a/doc/12-icinga2-api.md b/doc/12-icinga2-api.md index 58aaf6873..676bc9784 100644 --- a/doc/12-icinga2-api.md +++ b/doc/12-icinga2-api.md @@ -208,23 +208,27 @@ The [regex function](18-library-reference.md#global-functions-regex) is availabl More information about filters can be found in the [filters](12-icinga2-api.md#icinga2-api-filters) chapter. +Note that the permissions a API user has also specify the max body size of their requests. +A API user with `*` permissions is allowed to send 512 MB. + + Available permissions for specific URL endpoints: - Permissions | URL Endpoint | Supports Filters - ------------------------------|---------------|----------------- - actions/<action> | /v1/actions | Yes - config/query | /v1/config | No - config/modify | /v1/config | No - console | /v1/console | No - events/<type> | /v1/events | No - objects/query/<type> | /v1/objects | Yes - objects/create/<type> | /v1/objects | No - objects/modify/<type> | /v1/objects | Yes - objects/delete/<type> | /v1/objects | Yes - status/query | /v1/status | Yes - templates/<type> | /v1/templates | Yes - types | /v1/types | Yes - variables | /v1/variables | Yes + Permissions | URL Endpoint | Supports Filters | Max Body Size in MB + ------------------------------|---------------|-------------------|--------------------- + actions/<action> | /v1/actions | Yes | 1 + config/query | /v1/config | No | 1 + config/modify | /v1/config | No | 512 + console | /v1/console | No | 512 + events/<type> | /v1/events | No | 1 + objects/query/<type> | /v1/objects | Yes | 1 + objects/create/<type> | /v1/objects | No | 512 + objects/modify/<type> | /v1/objects | Yes | 512 + objects/delete/<type> | /v1/objects | Yes | 512 + status/query | /v1/status | Yes | 1 + templates/<type> | /v1/templates | Yes | 1 + types | /v1/types | Yes | 1 + variables | /v1/variables | Yes | 1 The required actions or types can be replaced by using a wildcard match ("\*"). diff --git a/lib/remote/apiuser.cpp b/lib/remote/apiuser.cpp index 416eedb34..7bd953880 100644 --- a/lib/remote/apiuser.cpp +++ b/lib/remote/apiuser.cpp @@ -36,7 +36,8 @@ ApiUser::Ptr ApiUser::GetByClientCN(const String& cn) return nullptr; } -ApiUser::Ptr ApiUser::GetByAuthHeader(const String& auth_header) { +ApiUser::Ptr ApiUser::GetByAuthHeader(const String& auth_header) +{ String::SizeType pos = auth_header.FindFirstOf(" "); String username, password; diff --git a/lib/remote/httpserverconnection.cpp b/lib/remote/httpserverconnection.cpp index 4fba15cb6..c9cdf5a3c 100644 --- a/lib/remote/httpserverconnection.cpp +++ b/lib/remote/httpserverconnection.cpp @@ -95,6 +95,7 @@ void HttpServerConnection::Disconnect() bool HttpServerConnection::ProcessMessage() { + bool res; HttpResponse response(m_Stream, m_CurrentRequest); @@ -186,6 +187,16 @@ bool HttpServerConnection::ProcessMessage() bool HttpServerConnection::ManageHeaders(HttpResponse& response) { + static const size_t defaultContentLengthLimit = 1 * 1028 * 1028; + static const Dictionary::Ptr specialContentLengthLimits = new Dictionary({ + {"*", 512 * 1028 * 1028}, + {"config/modify", 512 * 1028 * 1028}, + {"console", 512 * 1028 * 1028}, + {"objects/create", 512 * 1028 * 1028}, + {"objects/modify", 512 * 1028 * 1028}, + {"objects/delete", 512 * 1028 * 1028} + }); + if (m_CurrentRequest.Headers->Get("expect") == "100-continue") { String continueResponse = "HTTP/1.1 100 Continue\r\n\r\n"; m_Stream->Write(continueResponse.CStr(), continueResponse.GetLength()); @@ -276,6 +287,29 @@ bool HttpServerConnection::ManageHeaders(HttpResponse& response) return false; } + size_t maxSize = defaultContentLengthLimit; + + Array::Ptr permissions = m_AuthenticatedUser->GetPermissions(); + ObjectLock olock(permissions); + + for (const Value& permission : permissions) { + std::vector permissionParts = String(permission).Split("/"); + String permissionPath = permissionParts[0] + (permissionParts.size() > 1 ? "/" + permissionParts[1] : ""); + int size = specialContentLengthLimits->Get(permissionPath); + maxSize = size > maxSize ? size : maxSize; + } + + size_t contentLength = m_CurrentRequest.Headers->Get("content-length"); + + if (contentLength > maxSize) { + response.SetStatus(400, "Bad Request"); + String msg = String("

Content length exceeded maximum

"); + response.WriteBody(msg.CStr(), msg.GetLength()); + response.Finish(); + + return false; + } + return true; }