]> granicus.if.org Git - icinga2/commitdiff
Limit HTTP body size
authorNoah Hilverling <noah.hilverling@icinga.com>
Mon, 19 Feb 2018 12:33:58 +0000 (13:33 +0100)
committerJean Flach <jean-marcel.flach@icinga.com>
Fri, 23 Feb 2018 09:09:28 +0000 (10:09 +0100)
doc/12-icinga2-api.md
lib/remote/apiuser.cpp
lib/remote/httpserverconnection.cpp

index 15471e9c693845420841120614af979d23547435..acebac6e1ca5c5d3fbfa9243146f5ae4fde6cb3d 100644 (file)
@@ -201,23 +201,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/&lt;action&gt;        | /v1/actions   | Yes
-  config/query                  | /v1/config    | No
-  config/modify                 | /v1/config    | No
-  console                       | /v1/console   | No
-  events/&lt;type&gt;           | /v1/events    | No
-  objects/query/&lt;type&gt;    | /v1/objects   | Yes
-  objects/create/&lt;type&gt;   | /v1/objects   | No
-  objects/modify/&lt;type&gt;   | /v1/objects   | Yes
-  objects/delete/&lt;type&gt;   | /v1/objects   | Yes
-  status/query                  | /v1/status    | Yes
-  templates/&lt;type&gt;        | /v1/templates | Yes
-  types                         | /v1/types     | Yes
-  variables                     | /v1/variables | Yes
+  Permissions                   | URL Endpoint  | Supports Filters  | Max Body Size in MB
+  ------------------------------|---------------|-------------------|---------------------
+  actions/&lt;action&gt;        | /v1/actions   | Yes               | 1
+  config/query                  | /v1/config    | No                | 1
+  config/modify                 | /v1/config    | No                | 512
+  console                       | /v1/console   | No                | 512
+  events/&lt;type&gt;           | /v1/events    | No                | 1
+  objects/query/&lt;type&gt;    | /v1/objects   | Yes               | 1
+  objects/create/&lt;type&gt;   | /v1/objects   | No                | 512
+  objects/modify/&lt;type&gt;   | /v1/objects   | Yes               | 512
+  objects/delete/&lt;type&gt;   | /v1/objects   | Yes               | 512
+  status/query                  | /v1/status    | Yes               | 1
+  templates/&lt;type&gt;        | /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 ("\*").
 
index fedcd7163695d59889f806f3088102029405fb26..c3e95ebe6b89c4bcc6d89e5535c523743b8786f2 100644 (file)
@@ -36,7 +36,8 @@ ApiUser::Ptr ApiUser::GetByClientCN(const String& cn)
        return ApiUser::Ptr();
 }
 
-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;
 
index 8b0bb5ce685a9b10e664b550d6edb17ef6a53ead..ae284df34204fff6f024ca0fead260a61ce4a797 100644 (file)
@@ -95,6 +95,7 @@ void HttpServerConnection::Disconnect(void)
 
 bool HttpServerConnection::ProcessMessage(void)
 {
+
        bool res;
        HttpResponse response(m_Stream, m_CurrentRequest);
 
@@ -186,6 +187,16 @@ bool HttpServerConnection::ProcessMessage(void)
 
 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<String> 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("<h1>Content length exceeded maximum</h1>");
+               response.WriteBody(msg.CStr(), msg.GetLength());
+               response.Finish();
+
+               return false;
+       }
+
        return true;
 }