Changeset - d0d08adf5a6e
[Not reviewed]
0 6 0
Jan Kaluza - 10 years ago 2016-01-20 08:20:45
jkaluza@redhat.com
Web interface: allow using service.cert PEM certificate to enable SSL support.
6 files changed with 34 insertions and 1 deletions:
0 comments (0 inline, 0 general)
spectrum_manager/src/CMakeLists.txt
Show inline comments
 
cmake_minimum_required(VERSION 2.6)
 
FILE(GLOB SRC *.cpp *.c)
 

	
 
ADD_EXECUTABLE(spectrum2_manager ${SRC})
 

	
 
ADD_DEPENDENCIES(spectrum2_manager pb)
 
SET_SOURCE_FILES_PROPERTIES(${CMAKE_CURRENT_SOURCE_DIR}/../../include/transport/protocol.pb.cc PROPERTIES GENERATED 1)
 

	
 
target_link_libraries(spectrum2_manager transport ${SWIFTEN_LIBRARY} ${PROTOBUF_LIBRARIES})
 

	
 
if (CMAKE_COMPILER_IS_GNUCXX)
 
add_definitions(-DMG_ENABLE_SSL)
 
target_link_libraries(spectrum2_manager ${OPENSSL_LIBRARIES})
 
endif()
 

	
 
if(APPLE)
 
target_link_libraries(spectrum2_manager transport ${APPLE_FRAMEWORKS})
 
endif()
 
INSTALL(TARGETS spectrum2_manager RUNTIME DESTINATION bin)
 

	
 
INSTALL(FILES
 
	spectrum_manager.cfg
 
	DESTINATION /etc/spectrum2
 
	)
 

	
 
INSTALL(DIRECTORY
 
	html
 
	DESTINATION /var/lib/spectrum2_manager
 
	)
spectrum_manager/src/html/js/app.js
Show inline comments
 
function show_instances() {
 
	$.get("/api/v1/instances", function(data) {
 
		$("#main_content").html("<h2>List of Spectrum 2 instances</h2><table id='main_result'><tr><th>Name<th>Status</th><th>Actions</th></tr>");
 

	
 
		var admin = $.cookie("admin") == "1";
 
		$.each(data.instances, function(i, instance) {
 
			if (instance.running) {
 
				if (admin) {
 
					var command = instance.running ? "stop" : "start";
 
				}
 
				else {
 
					var command = instance.registered ? "unregister" : "register";
 
					if (instance.registered) {
 
						instance.status += "<br/>Registered as " + instance.username;
 
					}
 
				}
 
			}
 
			else if (admin) {
 
				var command = "start";
 
			}
 
			else {
 
				var command = "";
 
			}
 
			var row = '<tr>'
 
			row += '<td>' + instance.name + '</td>'
 
			row += '<td>' + instance.status + '</td>'
 

	
 
			if (command == 'register') {
 
				row += '<td><a class="button_command" href="/instances/register.shtml?id=' + instance.id + '">' + command + '</a>' + '</td></tr>';
 
				$("#main_result  > tbody:last-child").append(row);
 
			}
 
			else if (command == "") {
 
				row += '<td></td></tr>';
 
				$("#main_result  > tbody:last-child").append(row);
 
			}
 
			else {
 
				row += '<td><a class="button_command" href="/api/v1/instances/' + command + '/' + instance.id + '">' + command + '</a>' + '</td></tr>';
 
				$("#main_result  > tbody:last-child").append(row);
 
				$(".button_command").click(function(e) {
 
					e.preventDefault();
 
					$(this).parent().empty().progressbar( {value: false} ).css('height', '1em');
 

	
 
					var url = $(this).attr('href');
 
					$.get(url, function(data) {
 
						show_instances();
 
					});
 
				})
 
			}
 
		});
 
	});
 
}
 

	
 
function getQueryParams(qs) {
 
	qs = qs.split('+').join(' ');
 

	
 
	var params = {},
 
		tokens,
 
		re = /[?&]?([^=]+)=([^&]*)/g;
 

	
 
	while (tokens = re.exec(qs)) {
 
		params[decodeURIComponent(tokens[1])] = decodeURIComponent(tokens[2]);
 
	}
spectrum_manager/src/managerconfig.cpp
Show inline comments
 
@@ -11,48 +11,49 @@
 
 * This program is distributed in the hope that it will be useful,
 
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
 * GNU General Public License for more details.
 
 *
 
 * You should have received a copy of the GNU General Public License
 
 * along with this program; if not, write to the Free Software
 
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
 
 */
 

	
 
#include "managerconfig.h"
 
#include <fstream>
 

	
 
using namespace boost::program_options;
 

	
 
bool ManagerConfig::load(const std::string &configfile, boost::program_options::options_description &opts) {
 
	std::ifstream ifs(configfile.c_str());
 
	if (!ifs.is_open())
 
		return false;
 

	
 
	opts.add_options()
 
		("service.admin_username", value<std::string>()->default_value(""), "Administrator username.")
 
		("service.admin_password", value<std::string>()->default_value(""), "Administrator password.")
 
		("service.port", value<int>()->default_value(8081), "Web interface port.")
 
		("service.cert", value<std::string>()->default_value(""), "Web interface certificate in PEM format when TLS should be used.")
 
		("service.config_directory", value<std::string>()->default_value("/etc/spectrum2/transports/"), "Directory with spectrum2 configuration files. One .cfg file per one instance")
 
		("service.data_dir", value<std::string>()->default_value("/var/lib/spectrum2_manager/html"), "Directory to store Spectrum 2 manager data")
 
		("servers.server", value<std::vector<std::string> >()->multitoken(), "Server.")
 
		("database.type", value<std::string>()->default_value("none"), "Database type.")
 
		("database.database", value<std::string>()->default_value("/var/lib/spectrum2/$jid/database.sql"), "Database used to store data")
 
		("database.server", value<std::string>()->default_value("localhost"), "Database server.")
 
		("database.user", value<std::string>()->default_value(""), "Database user.")
 
		("database.password", value<std::string>()->default_value(""), "Database Password.")
 
		("database.port", value<int>()->default_value(0), "Database port.")
 
		("database.prefix", value<std::string>()->default_value(""), "Prefix of tables in database")
 
	;
 

	
 
	store(parse_config_file(ifs, opts), m_variables);
 
	notify(m_variables);
 

	
 
	m_file = configfile;
 

	
 
	onManagerConfigReloaded();
 

	
 
	return true;
 
}
 

	
 
bool ManagerConfig::load(const std::string &configfile) {
 
	options_description opts("Transport options");
spectrum_manager/src/mongoose.c
Show inline comments
 
@@ -2207,48 +2207,49 @@ Z9bmgaP+sfQwGpVlv9mtaWjvERbu6mEG7JTkgmVUJrUt/wiRzwTaCXBqZkdUO8Tq\n\
 
+E6VOEQAilstG90ikN1Tfo+K6+X68XkRUIlgawBTKuvKVwBhuvlqTGerOtnXWnrt\n\
 
ym//hd3cd5PBYGBix0i7oR4xdghvfR2WLVu0LgdThTBb6XP7gLd19cQ1JuBtAajZ\n\
 
wMuPn7qlUkEFDIkAZy59/Hue/H2Q2vU/JsvVhHWCQBL4F1ofEAt50il6ZxR1QfFK\n\
 
9VGKDC4oOgm9DlxwwBoC2FjqmvQlqVV3kwIBAg==\n\
 
-----END DH PARAMETERS-----\n";
 
#endif
 

	
 
static int mg_use_ca_cert(SSL_CTX *ctx, const char *cert) {
 
  if (ctx == NULL) {
 
    return -1;
 
  } else if (cert == NULL || cert[0] == '\0') {
 
    return 0;
 
  }
 
  SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, 0);
 
  return SSL_CTX_load_verify_locations(ctx, cert, NULL) == 1 ? 0 : -2;
 
}
 

	
 
static int mg_use_cert(SSL_CTX *ctx, const char *pem_file) {
 
  if (ctx == NULL) {
 
    return -1;
 
  } else if (pem_file == NULL || pem_file[0] == '\0') {
 
    return 0;
 
  } else if (SSL_CTX_use_certificate_file(ctx, pem_file, 1) == 0 ||
 
             SSL_CTX_use_PrivateKey_file(ctx, pem_file, 1) == 0) {
 
	  ERR_print_errors_fp(stderr);
 
    return -2;
 
  } else {
 
#ifndef MG_DISABLE_PFS
 
    BIO *bio = NULL;
 
    DH *dh = NULL;
 

	
 
    /* Try to read DH parameters from the cert/key file. */
 
    bio = BIO_new_file(pem_file, "r");
 
    if (bio != NULL) {
 
      dh = PEM_read_bio_DHparams(bio, NULL, NULL, NULL);
 
      BIO_free(bio);
 
    }
 
    /*
 
     * If there are no DH params in the file, fall back to hard-coded ones.
 
     * Not ideal, but better than nothing.
 
     */
 
    if (dh == NULL) {
 
      bio = BIO_new_mem_buf((void *) mg_s_default_dh_params, -1);
 
      dh = PEM_read_bio_DHparams(bio, NULL, NULL, NULL);
 
      BIO_free(bio);
 
    }
 
    if (dh != NULL) {
 
      SSL_CTX_set_tmp_dh(ctx, dh);
 
      SSL_CTX_set_options(ctx, SSL_OP_SINGLE_DH_USE);
spectrum_manager/src/mongoose.h
Show inline comments
 
@@ -623,48 +623,49 @@ int json_emit_va(char *buf, int buf_len, const char *fmt, va_list);
 
/*
 
 * === Core: TCP/UDP/SSL
 
 *
 
 * NOTE: Mongoose manager is single threaded. It does not protect
 
 * its data structures by mutexes, therefore all functions that are dealing
 
 * with particular event manager should be called from the same thread,
 
 * with exception of `mg_broadcast()` function. It is fine to have different
 
 * event managers handled by different threads.
 
 */
 

	
 
#ifndef MG_NET_HEADER_INCLUDED
 
#define MG_NET_HEADER_INCLUDED
 

	
 
#ifdef MG_ENABLE_JAVASCRIPT
 
#define EXCLUDE_COMMON
 
#include <v7.h>
 
#endif
 

	
 

	
 
#ifdef MG_ENABLE_SSL
 
#ifdef __APPLE__
 
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
 
#endif
 
#include <openssl/ssl.h>
 
#include <openssl/err.h>
 
#else
 
typedef void *SSL;
 
typedef void *SSL_CTX;
 
#endif
 

	
 
#ifdef MG_USE_READ_WRITE
 
#define MG_RECV_FUNC(s, b, l, f) read(s, b, l)
 
#define MG_SEND_FUNC(s, b, l, f) write(s, b, l)
 
#else
 
#define MG_RECV_FUNC(s, b, l, f) recv(s, b, l, f)
 
#define MG_SEND_FUNC(s, b, l, f) send(s, b, l, f)
 
#endif
 

	
 
#ifdef __cplusplus
 
extern "C" {
 
#endif /* __cplusplus */
 

	
 
union socket_address {
 
  struct sockaddr sa;
 
  struct sockaddr_in sin;
 
#ifdef MG_ENABLE_IPV6
 
  struct sockaddr_in6 sin6;
 
#else
 
  struct sockaddr sin6;
spectrum_manager/src/server.cpp
Show inline comments
 
@@ -42,49 +42,66 @@ static std::string get_http_var(const struct http_message *hm, const char *name)
 
static void my_strlcpy(char *dst, const char *src, size_t len) {
 
  strncpy(dst, src, len);
 
  dst[len - 1] = '\0';
 
}
 

	
 
// Generate session ID. buf must be 33 bytes in size.
 
// Note that it is easy to steal session cookies by sniffing traffic.
 
// This is why all communication must be SSL-ed.
 
static void generate_session_id(char *buf, const char *random,
 
                                const char *user) {
 
  cs_md5(buf, random, strlen(random), user, strlen(user), NULL);
 
}
 

	
 
static void _event_handler(struct mg_connection *nc, int ev, void *p) {
 
	static_cast<Server *>(nc->mgr->user_data)->event_handler(nc, ev, p);
 
}
 

	
 
Server::Server(ManagerConfig *config, const std::string &config_file) {
 
	srand((unsigned) time(0));
 
	m_config = config;
 
	m_user = CONFIG_STRING(m_config, "service.admin_username");
 
	m_password = CONFIG_STRING(m_config, "service.admin_password");
 

	
 
	mg_mgr_init(&m_mgr, this);
 
	m_nc = mg_bind(&m_mgr, std::string(":" + boost::lexical_cast<std::string>(CONFIG_INT(m_config, "service.port"))).c_str(), &_event_handler);
 

	
 
	struct mg_bind_opts opts;
 
	memset(&opts, 0, sizeof(opts));
 
	const char *error_string;
 
	opts.error_string = &error_string;
 
	m_nc = mg_bind_opt(&m_mgr, std::string(":" + boost::lexical_cast<std::string>(CONFIG_INT(m_config, "service.port"))).c_str(), &_event_handler, opts);
 
	if (!m_nc) {
 
		std::cerr << "Error creating server: " << error_string << "\n";
 
		exit(1);
 
	}
 

	
 
	if (!CONFIG_STRING(m_config, "service.cert").empty()) {
 
		const char *err_str = mg_set_ssl(m_nc, CONFIG_STRING(m_config, "service.cert").c_str(), NULL);
 
		if (err_str) {
 
			std::cerr << "Error setting SSL certificate: " << err_str << "\n";
 
			exit(1);
 
		}
 
	}
 
	mg_set_protocol_http_websocket(m_nc);
 

	
 
	s_http_server_opts.document_root = CONFIG_STRING(m_config, "service.data_dir").c_str();
 

	
 
	std::ifstream header(std::string(CONFIG_STRING(m_config, "service.data_dir") + "/header.html").c_str(), std::ios::in);
 
	if (header) {
 
		header.seekg(0, std::ios::end);
 
		m_header.resize(header.tellg());
 
		header.seekg(0, std::ios::beg);
 
		header.read(&m_header[0], m_header.size());
 
		header.close();
 
	}
 

	
 
	std::ifstream footer(std::string(CONFIG_STRING(m_config, "service.data_dir") + "/footer.html").c_str(), std::ios::in);
 
	if (footer) {
 
		footer.seekg(0, std::ios::end);
 
		m_footer.resize(footer.tellg());
 
		footer.seekg(0, std::ios::beg);
 
		footer.read(&m_footer[0], m_footer.size());
 
		footer.close();
 
	}
 

	
 
	m_storageCfg = new Config();
 
	m_storageCfg->load(config_file);
0 comments (0 inline, 0 general)