diff --git a/doc/samples/keepalived.conf.HTTP_GET.auth b/doc/samples/keepalived.conf.HTTP_GET.auth new file mode 100644 index 0000000000..29e9996825 --- /dev/null +++ b/doc/samples/keepalived.conf.HTTP_GET.auth @@ -0,0 +1,64 @@ +! Configuration File for keepalived - HTTP_GET with authentication +! This sample demonstrates HTTP basic authentication for HTTP_GET checks + +global_defs { + notification_email { + acassen + } + notification_email_from Alexandre.Cassen@firewall.loc + smtp_server 192.168.200.1 + smtp_connect_timeout 30 + router_id LVS_DEVEL +} + +vrrp_instance VI_1 { + interface lo + virtual_router_id 50 + nopreempt + priority 100 + advert_int 1 + virtual_ipaddress { + 127.0.0.1 + } +} + +virtual_server 10.10.10.2 1358 { + delay_loop 6 + lb_algo rr + lb_kind NAT + persistence_timeout 50 + protocol TCP + + sorry_server 192.168.200.200 1358 + + real_server 192.168.200.2 1358 { + weight 1 + HTTP_GET { + url { + path /testurl3/test.jsp + username myuser + password mypassword + status_code 200 + } + connect_timeout 3 + retry 3 + delay_before_retry 3 + } + } + + real_server 192.168.200.3 1358 { + weight 1 + SSL_GET { + url { + path /secure/test.jsp + username admin + password secret123 + status_code 200 + tls_compliant + } + connect_timeout 5 + retry 3 + delay_before_retry 3 + } + } +} diff --git a/doc/samples/keepalived.conf.HTTP_GET.auth.simple b/doc/samples/keepalived.conf.HTTP_GET.auth.simple new file mode 100644 index 0000000000..29313388ca --- /dev/null +++ b/doc/samples/keepalived.conf.HTTP_GET.auth.simple @@ -0,0 +1,51 @@ +! Simple configuration to test HTTP_GET authentication +! This tests only the HTTP check parsing without VRRP + +global_defs { + notification_email { + acassen + } + notification_email_from Alexandre.Cassen@firewall.loc + smtp_server 192.168.200.1 + smtp_connect_timeout 30 + router_id LVS_DEVEL +} + +virtual_server 10.10.10.2 1358 { + delay_loop 6 + lb_algo rr + lb_kind NAT + persistence_timeout 50 + protocol TCP + + real_server 127.0.0.1 1358 { + weight 1 + HTTP_GET { + url { + path /testurl3/test.jsp + username myuser + password mypassword + status_code 200 + } + connect_timeout 3 + retry 3 + delay_before_retry 3 + } + } + + real_server 127.0.0.1 1359 { + weight 1 + SSL_GET { + url { + path /secure/test.jsp + username admin + password secret123 + status_code 200 + tls_compliant + } + connect_timeout 5 + retry 3 + delay_before_retry 3 + } + } +} diff --git a/keepalived/check/check_http.c b/keepalived/check/check_http.c index 9d3dbb8e80..4c33b32d63 100644 --- a/keepalived/check/check_http.c +++ b/keepalived/check/check_http.c @@ -128,12 +128,14 @@ static const char *request_template = "GET %s HTTP/1.%d\r\n" "User-Agent: KeepAliveClient\r\n" "%s" + "%s" "Host: %s%s\r\n\r\n"; static const char *request_template_ipv6 = "GET %s HTTP/1.%d\r\n" "User-Agent: KeepAliveClient\r\n" "%s" + "%s" "Host: [%s]%s\r\n\r\n"; /* Output delimiters */ @@ -177,6 +179,8 @@ free_url(url_t *url) FREE_CONST_PTR(url->path); FREE_CONST_PTR(url->digest); FREE_CONST_PTR(url->virtualhost); + FREE_CONST_PTR(url->username); + FREE_CONST_PTR(url->password); #ifdef _WITH_REGEX_CHECK_ if (url->regex) { if (!--url->regex->refcnt) { @@ -259,6 +263,8 @@ dump_url(FILE *fp, bool is_ssl, const url_t *url) if (url->virtualhost) conf_write(fp, " Virtual host = %s", url->virtualhost); + if (url->username && url->password) + conf_write(fp, " Auth = %s:%s", url->username, url->password); if (url->last_ssl_error) conf_write(fp, " Last SSL error = 0x%lx", url->last_ssl_error); @@ -412,6 +418,14 @@ compare_http_check(const checker_t *old_c, checker_t *new_c) return false; if (u1->virtualhost && strcmp(u1->virtualhost, u2->virtualhost)) return false; + if (!u1->username != !u2->username) + return false; + if (u1->username && strcmp(u1->username, u2->username)) + return false; + if (!u1->password != !u2->password) + return false; + if (u1->password && strcmp(u1->password, u2->password)) + return false; #ifdef _WITH_REGEX_CHECK_ if (!u1->regex != !u2->regex) return false; @@ -617,6 +631,28 @@ url_virtualhost_handler(const vector_t *strvec) set_string(¤t_url->virtualhost, strvec, "url virtualhost"); } +static void +url_username_handler(const vector_t *strvec) +{ + if (vector_size(strvec) < 2) { + report_config_error(CONFIG_GENERAL_ERROR, "Missing HTTP_GET username"); + return; + } + + set_string(¤t_url->username, strvec, "url username"); +} + +static void +url_password_handler(const vector_t *strvec) +{ + if (vector_size(strvec) < 2) { + report_config_error(CONFIG_GENERAL_ERROR, "Missing HTTP_GET password"); + return; + } + + set_string(¤t_url->password, strvec, "url password"); +} + static void url_tls_compliant_handler(const vector_t *strvec) { @@ -962,6 +998,8 @@ install_http_ssl_check_keyword(const char *keyword) install_keyword("digest", &digest_handler); install_keyword("status_code", &status_code_handler); install_keyword("virtualhost", &url_virtualhost_handler); + install_keyword("username", &url_username_handler); + install_keyword("password", &url_password_handler); #ifdef _WITH_REGEX_CHECK_ install_keyword("regex", ®ex_handler); install_keyword("regex_no_match", ®ex_no_match_handler); @@ -1642,6 +1680,8 @@ http_request(thread_ref_t thread) const char *request_host; char request_host_port[7]; /* ":" [0-9][0-9][0-9][0-9][0-9] "\0" */ char *str_request; + const char *auth_header = ""; + char auth_buf[512]; url_t *fetched_url; int ret = 0; @@ -1650,6 +1690,21 @@ http_request(thread_ref_t thread) fetched_url = fetch_next_url(http_get_check); + /* Create Authorization header if username and password are provided */ + if (fetched_url->username && fetched_url->password) { + char credentials[128]; + char encoded[256]; + int len; + + snprintf(credentials, sizeof(credentials), "%s:%s", fetched_url->username, fetched_url->password); + len = EVP_EncodeBlock((unsigned char *)encoded, (unsigned char *)credentials, strlen(credentials)); + if (len > 0) { + encoded[len] = '\0'; + snprintf(auth_buf, sizeof(auth_buf), "Authorization: Basic %s\r\n", encoded); + auth_header = auth_buf; + } + } + if (fetched_url->virtualhost) vhost = fetched_url->virtualhost; else if (http_get_check->virtualhost) @@ -1677,6 +1732,7 @@ http_request(thread_ref_t thread) fetched_url->path, http_get_check->http_protocol == HTTP_PROTOCOL_1_1 ? 1 : 0, http_get_check->http_protocol == HTTP_PROTOCOL_1_0C || http_get_check->http_protocol == HTTP_PROTOCOL_1_1 ? "Connection: close\r\n" : "", + auth_header, request_host, request_host_port); #ifdef _CHECKER_DEBUG_ diff --git a/keepalived/include/check_http.h b/keepalived/include/check_http.h index 382e59584d..034479e0ac 100644 --- a/keepalived/include/check_http.h +++ b/keepalived/include/check_http.h @@ -99,6 +99,8 @@ typedef struct _url { const uint8_t *digest; unsigned long status_code[(HTTP_STATUS_CODE_MAX - HTTP_STATUS_CODE_MIN + 1 - 1) / (sizeof(unsigned long) * CHAR_BIT) + 1]; const char *virtualhost; + const char *username; + const char *password; ssize_t len_mismatch; bool tls_compliant; unsigned long last_ssl_error;