Configuration Attributes:
- Name |Description
- --------------------------|--------------------------
- cert\_path |**Required.** Path to the public key.
- key\_path |**Required.** Path to the private key.
- ca\_path |**Required.** Path to the CA certificate file.
- ticket\_salt |**Optional.** Private key for auto-signing. **Required** for a signing master instance.
- crl\_path |**Optional.** Path to the CRL file.
- bind\_host |**Optional.** The IP address the api listener should be bound to. Defaults to `0.0.0.0`.
- bind\_port |**Optional.** The port the api listener should be bound to. Defaults to `5665`.
- accept\_config |**Optional.** Accept zone configuration. Defaults to `false`.
- accept\_commands |**Optional.** Accept remote commands. Defaults to `false`.
- cipher\_list |**Optional.** Cipher list that is allowed.
- tls\_protocolmin |**Optional.** Minimum TLS protocol version. Must be one of `TLSv1`, `TLSv1.1` or `TLSv1.2`. Defaults to `TLSv1`.
+ Name |Description
+ --------------------------------------|--------------------------------------
+ cert\_path |**Required.** Path to the public key.
+ key\_path |**Required.** Path to the private key.
+ ca\_path |**Required.** Path to the CA certificate file.
+ ticket\_salt |**Optional.** Private key for auto-signing. **Required** for a signing master instance.
+ crl\_path |**Optional.** Path to the CRL file.
+ bind\_host |**Optional.** The IP address the api listener should be bound to. Defaults to `0.0.0.0`.
+ bind\_port |**Optional.** The port the api listener should be bound to. Defaults to `5665`.
+ accept\_config |**Optional.** Accept zone configuration. Defaults to `false`.
+ accept\_commands |**Optional.** Accept remote commands. Defaults to `false`.
+ cipher\_list |**Optional.** Cipher list that is allowed.
+ tls\_protocolmin |**Optional.** Minimum TLS protocol version. Must be one of `TLSv1`, `TLSv1.1` or `TLSv1.2`. Defaults to `TLSv1`.
+ access\_control\_allow\_origin |**Optional.** Specifies an array of origin URLs that may access the API. [(MDN docs)](https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS#Access-Control-Allow-Origin)
+ access\_control\_allow\_credentials |**Optional.** Indicates whether or not the actual request can be made using credentials. Defaults to `true`. [(MDN docs)](https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS#Access-Control-Allow-Credentials)
+ access\_control\_allow\_headers |**Optional.** Used in response to a preflight request to indicate which HTTP headers can be used when making the actual request. Defaults to `Authorization`. [(MDN docs)](https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS#Access-Control-Allow-Headers)
+ access\_control\_allow\_methods |**Optional.** Used in response to a preflight request to indicate which HTTP methods can be used when making the actual request. Defaults to `GET, POST, PUT, DELETE`. [(MDN docs)](https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS#Access-Control-Allow-Methods)
## ApiUser <a id="objecttype-apiuser"></a>
[config] String ticket_salt;
+ [config] array(String) access_control_allow_origin {
+ default {{{ return new Array(); }}}
+ };
+ [config] bool access_control_allow_credentials
+ {
+ default {{{ return true; }}}
+ };
+ [config] String access_control_allow_headers
+ {
+ default {{{ return "Authorization"; }}}
+ };
+ [config] String access_control_allow_methods
+ {
+ default {{{ return "GET, POST, PUT, DELETE"; }}}
+ };
+
+
[state, no_user_modify] Timestamp log_message_timestamp;
[no_user_modify] String identity;
void HttpResponse::AddHeader(const String& key, const String& value)
{
- if (m_State != HttpResponseHeaders) {
- Log(LogWarning, "HttpResponse", "Tried to add header after headers had already been sent.");
- return;
- }
-
- String header = key + ": " + value + "\r\n";
- m_Stream->Write(header.CStr(), header.GetLength());
+ m_Headers.push_back(key + ": " + value + "\r\n");
}
void HttpResponse::FinishHeaders(void)
AddHeader("Transfer-Encoding", "chunked");
AddHeader("Server", "Icinga/" + Application::GetAppVersion());
+
+ for (const String& header : m_Headers)
+ m_Stream->Write(header.CStr(), header.GetLength());
+
m_Stream->Write("\r\n", 2);
m_State = HttpResponseBody;
}
#include "remote/httprequest.hpp"
#include "base/stream.hpp"
#include "base/fifo.hpp"
+#include <vector>
namespace icinga
{
const HttpRequest& m_Request;
Stream::Ptr m_Stream;
FIFO::Ptr m_Body;
+ std::vector<String> m_Headers;
void FinishHeaders(void);
};
HttpResponse response(m_Stream, request);
+ ApiListener::Ptr listener = ApiListener::GetInstance();
+
+ if (!listener)
+ return;
+
+ Array::Ptr headerAllowOrigin = listener->GetAccessControlAllowOrigin();
+
+ if (headerAllowOrigin->GetLength() != 0) {
+ String origin = request.Headers->Get("origin");
+
+ {
+ ObjectLock olock(headerAllowOrigin);
+
+ for (const String& allowedOrigin : headerAllowOrigin) {
+ if (allowedOrigin == origin)
+ response.AddHeader("Access-Control-Allow-Origin", origin);
+ }
+ }
+
+ if (listener->GetAccessControlAllowCredentials())
+ response.AddHeader("Access-Control-Allow-Credentials", "true");
+
+ String accessControlRequestMethodHeader = request.Headers->Get("access-control-request-method");
+
+ if (!accessControlRequestMethodHeader.IsEmpty()) {
+ response.SetStatus(200, "OK");
+
+ response.AddHeader("Access-Control-Allow-Methods", listener->GetAccessControlAllowMethods());
+ response.AddHeader("Access-Control-Allow-Headers", listener->GetAccessControlAllowHeaders());
+
+ String msg = "Preflight OK";
+ response.WriteBody(msg.CStr(), msg.GetLength());
+
+ response.Finish();
+ m_PendingRequests--;
+
+ return;
+ }
+ }
+
String accept_header = request.Headers->Get("accept");
if (request.RequestMethod != "GET" && accept_header != "application/json") {