MXS-1220: Add HTTPS support

The REST API now supports encryption. The user needs to configure
certificates for the REST API before encryption is used.
This commit is contained in:
Markus Mäkelä
2017-05-02 07:12:44 +03:00
parent 4ed4773d91
commit bf44cd0d14
6 changed files with 167 additions and 32 deletions

View File

@ -18,7 +18,9 @@
#include <climits>
#include <new>
#include <fstream>
#include <microhttpd.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
@ -29,14 +31,23 @@
#include <maxscale/utils.h>
#include <maxscale/config.h>
#include <maxscale/hk_heartbeat.h>
#include <sys/stat.h>
#include "maxscale/resource.hh"
#include "maxscale/http.hh"
using std::string;
using std::ifstream;
static struct MHD_Daemon* http_daemon = NULL;
/** In-memory certificates in PEM format */
static char* admin_ssl_key = NULL;
static char* admin_ssl_cert = NULL;
static char* admin_ssl_ca_cert = NULL;
static bool using_ssl = false;
int kv_iter(void *cls,
enum MHD_ValueKind kind,
const char *key,
@ -221,6 +232,58 @@ static bool host_to_sockaddr(const char* host, uint16_t port, struct sockaddr_st
return true;
}
static char* load_cert(const char* file)
{
char* rval = NULL;
ifstream infile(file);
struct stat st;
if (stat(file, &st) == 0 &&
(rval = new (std::nothrow) char[st.st_size + 1]))
{
infile.read(rval, st.st_size);
rval[st.st_size] = '\0';
if (!infile.good())
{
MXS_ERROR("Failed to load certificate file: %s", file);
delete rval;
rval = NULL;
}
}
return rval;
}
static bool load_ssl_certificates()
{
bool rval = false;
const char* key = config_get_global_options()->admin_ssl_key;
const char* cert = config_get_global_options()->admin_ssl_cert;
const char* ca = config_get_global_options()->admin_ssl_ca_cert;
if (*key && *cert && *ca)
{
if ((admin_ssl_key = load_cert(key)) &&
(admin_ssl_cert = load_cert(cert)) &&
(admin_ssl_ca_cert = load_cert(ca)))
{
rval = true;
}
else
{
delete admin_ssl_key;
delete admin_ssl_cert;
delete admin_ssl_ca_cert;
admin_ssl_key = NULL;
admin_ssl_cert = NULL;
admin_ssl_ca_cert = NULL;
}
}
return rval;
}
bool mxs_admin_init()
{
struct sockaddr_storage addr;
@ -236,10 +299,20 @@ bool mxs_admin_init()
options |= MHD_USE_DUAL_STACK;
}
if (load_ssl_certificates())
{
using_ssl = true;
options |= MHD_USE_SSL;
}
// The port argument is ignored and the port in the struct sockaddr is used instead
http_daemon = MHD_start_daemon(options, 0, NULL, NULL, handle_client, NULL,
http_daemon = MHD_start_daemon(options, 0, NULL, NULL, handle_client, NULL,
MHD_OPTION_NOTIFY_COMPLETED, close_client, NULL,
MHD_OPTION_SOCK_ADDR, &addr,
!using_ssl ? MHD_OPTION_END :
MHD_OPTION_HTTPS_MEM_KEY, admin_ssl_key,
MHD_OPTION_HTTPS_MEM_CERT, admin_ssl_cert,
MHD_OPTION_HTTPS_MEM_TRUST, admin_ssl_cert,
MHD_OPTION_END);
}
@ -250,3 +323,8 @@ void mxs_admin_shutdown()
{
MHD_stop_daemon(http_daemon);
}
bool mxs_admin_https_enabled()
{
return using_ssl;
}

View File

@ -57,6 +57,9 @@ const char CN_ADMIN_HOST[] = "admin_host";
const char CN_ADMIN_PASSWORD[] = "admin_password";
const char CN_ADMIN_PORT[] = "admin_port";
const char CN_ADMIN_USER[] = "admin_user";
const char CN_ADMIN_SSL_KEY[] = "admin_ssl_key";
const char CN_ADMIN_SSL_CERT[] = "admin_ssl_cert";
const char CN_ADMIN_SSL_CA_CERT[] = "admin_ssl_ca_cert";
const char CN_AUTHENTICATOR[] = "authenticator";
const char CN_AUTHENTICATOR_OPTIONS[] = "authenticator_options";
const char CN_AUTH_ALL_SERVERS[] = "auth_all_servers";
@ -1525,6 +1528,18 @@ handle_global_item(const char *name, const char *value)
{
strcpy(gateway.admin_host, value);
}
else if (strcmp(name, CN_ADMIN_SSL_KEY) == 0)
{
strcpy(gateway.admin_ssl_key, value);
}
else if (strcmp(name, CN_ADMIN_SSL_CERT) == 0)
{
strcpy(gateway.admin_ssl_cert, value);
}
else if (strcmp(name, CN_ADMIN_SSL_CA_CERT) == 0)
{
strcpy(gateway.admin_ssl_ca_cert, value);
}
else if (strcmp(name, CN_ADMIN_AUTH) == 0)
{
gateway.admin_auth = config_truth_value(value);
@ -1754,6 +1769,9 @@ global_defaults()
strcpy(gateway.admin_host, DEFAULT_ADMIN_HOST);
strcpy(gateway.admin_user, INET_DEFAULT_USERNAME);
strcpy(gateway.admin_password, INET_DEFAULT_PASSWORD);
gateway.admin_ssl_key[0] = '\0';
gateway.admin_ssl_cert[0] = '\0';
gateway.admin_ssl_ca_cert[0] = '\0';
if (version_string != NULL)
{

View File

@ -12,6 +12,7 @@
*/
#include "maxscale/httprequest.hh"
#include "maxscale/admin.hh"
#include <ctype.h>
#include <string.h>
@ -98,8 +99,8 @@ HttpRequest::HttpRequest(struct MHD_Connection *connection, string url, string m
m_connection(connection)
{
process_uri(url, m_resource_parts);
// TODO: Add https support
m_hostname = HttpRequest::HTTP_PREFIX;
m_hostname = mxs_admin_https_enabled() ? HttpRequest::HTTPS_PREFIX : HttpRequest::HTTP_PREFIX;
m_hostname += get_header(HTTP_HOST_HEADER);
}

View File

@ -68,3 +68,10 @@ bool mxs_admin_init();
* @brief Shutdown the administrative interface
*/
void mxs_admin_shutdown();
/**
* @brief Check if admin interface uses HTTPS protocol
*
* @return True if HTTPS is enabled
*/
bool mxs_admin_https_enabled();