diff options
| author | Ed Tanous <ed.tanous@intel.com> | 2017-02-28 11:06:34 -0800 |
|---|---|---|
| committer | Ed Tanous <ed.tanous@intel.com> | 2017-02-28 11:06:34 -0800 |
| commit | 0fdddb1bd4b35419edbc8489db239d1bd2b0af9d (patch) | |
| tree | 8d9e7d965a279e42a2f67b000ff78d4eaf2647b9 /src | |
| download | bmcweb-0fdddb1bd4b35419edbc8489db239d1bd2b0af9d.tar.gz bmcweb-0fdddb1bd4b35419edbc8489db239d1bd2b0af9d.zip | |
initial commit
Diffstat (limited to 'src')
| -rw-r--r-- | src/ColorCoutG3Sink.hpp | 26 | ||||
| -rw-r--r-- | src/example.cpp | 199 | ||||
| -rw-r--r-- | src/ssl_key_handler.hpp | 182 |
3 files changed, 407 insertions, 0 deletions
diff --git a/src/ColorCoutG3Sink.hpp b/src/ColorCoutG3Sink.hpp new file mode 100644 index 0000000..cd98fac --- /dev/null +++ b/src/ColorCoutG3Sink.hpp @@ -0,0 +1,26 @@ +#pragma once +namespace crow +{ + struct ColorCoutSink { + + // Linux xterm color + // http://stackoverflow.com/questions/2616906/how-do-i-output-coloured-text-to-a-linux-terminal + enum FG_Color {YELLOW = 33, RED = 31, GREEN=32, WHITE = 97}; + + FG_Color GetColor(const LEVELS level) const { + if (level.value == WARNING.value) { return YELLOW; } + if (level.value == DEBUG.value) { return GREEN; } + if (g3::internal::wasFatal(level)) { return RED; } + + return WHITE; + } + + void ReceiveLogMessage(g3::LogMessageMover logEntry) { + auto level = logEntry.get()._level; + auto color = GetColor(level); + + std::cout << "\033[" << color << "m" + << logEntry.get().toString() << "\033[m"; + } + }; +}
\ No newline at end of file diff --git a/src/example.cpp b/src/example.cpp new file mode 100644 index 0000000..ed893e6 --- /dev/null +++ b/src/example.cpp @@ -0,0 +1,199 @@ +#include "crow/query_string.h" +#include "crow/http_parser_merged.h" +#include "crow/ci_map.h" +//#include "crow/TinySHA1.hpp" +#include "crow/settings.h" +#include "crow/socket_adaptors.h" +#include "crow/json.h" +#include "crow/mustache.h" +#include "crow/logging.h" +#include "crow/dumb_timer_queue.h" +#include "crow/utility.h" +#include "crow/common.h" +#include "crow/http_request.h" +#include "crow/websocket.h" +#include "crow/parser.h" +#include "crow/http_response.h" +#include "crow/middleware.h" +#include "crow/routing.h" +#include "crow/middleware_context.h" +#include "crow/http_connection.h" +#include "crow/http_server.h" +#include "crow/app.h" + +#include "ColorCoutG3Sink.hpp" + +#include "ssl_key_handler.hpp" +#include <iostream> +#include <string> + + + +struct ExampleMiddleware +{ + std::string message; + + ExampleMiddleware() + { + message = "foo"; + } + + void setMessage(std::string newMsg) + { + message = newMsg; + } + + struct context + { + }; + + void before_handle(crow::request& /*req*/, crow::response& /*res*/, context& /*ctx*/) + { + CROW_LOG_DEBUG << " - MESSAGE: " << message; + } + + void after_handle(crow::request& /*req*/, crow::response& /*res*/, context& /*ctx*/) + { + // no-op + } +}; + + + +int main(int argc, char** argv) +{ + auto worker = g3::LogWorker::createLogWorker(); + auto handle= worker->addDefaultLogger(argv[0], "/tmp/"); + g3::initializeLogging(worker.get()); + auto log_file_name = handle->call(&g3::FileSink::fileName); + auto stdout_handler = std::make_unique<crow::ColorCoutSink>(); + auto sink_handle = worker->addSink(stdout_handler, + &crow::ColorCoutSink::ReceiveLogMessage); + + LOG(DEBUG) << "Logging to " << log_file_name.get() << "\n"; + + std::string ssl_pem_file("server.pem"); + ensuressl::ensure_openssl_key_present_and_valid(ssl_pem_file); + //auto handler2 = std::make_shared<ExampleLogHandler>(); + //crow::logger::setHandler(handler2.get()); + crow::App<ExampleMiddleware> app; + + app.get_middleware<ExampleMiddleware>().setMessage("hello"); + + CROW_ROUTE(app, "/") + .name("hello") + ([]{ + return "Hello World!"; + }); + + CROW_ROUTE(app, "/about") + ([](){ + return "About Crow example."; + }); + + // a request to /path should be forwarded to /path/ + CROW_ROUTE(app, "/path/") + ([](){ + return "Trailing slash test case.."; + }); + + + // simple json response + // To see it in action enter {ip}:18080/json + CROW_ROUTE(app, "/json") + ([]{ + crow::json::wvalue x; + x["message"] = "Hello, World!"; + return x; + }); + + // To see it in action enter {ip}:18080/hello/{integer_between -2^32 and 100} and you should receive + // {integer_between -2^31 and 100} bottles of beer! + CROW_ROUTE(app,"/hello/<int>") + ([](int count){ + if (count > 100) + return crow::response(400); + std::ostringstream os; + os << count << " bottles of beer!"; + return crow::response(os.str()); + }); + + // To see it in action submit {ip}:18080/add/1/2 and you should receive 3 (exciting, isn't it) + CROW_ROUTE(app,"/add/<int>/<int>") + ([](const crow::request& /*req*/, crow::response& res, int a, int b){ + std::ostringstream os; + os << a+b; + res.write(os.str()); + res.end(); + }); + + // Compile error with message "Handler type is mismatched with URL paramters" + //CROW_ROUTE(app,"/another/<int>") + //([](int a, int b){ + //return crow::response(500); + //}); + + // more json example + + // To see it in action, I recommend to use the Postman Chrome extension: + // * Set the address to {ip}:18080/add_json + // * Set the method to post + // * Select 'raw' and then JSON + // * Add {"a": 1, "b": 1} + // * Send and you should receive 2 + + // A simpler way for json example: + // * curl -d '{"a":1,"b":2}' {ip}:18080/add_json + CROW_ROUTE(app, "/add_json") + .methods("POST"_method) + ([](const crow::request& req){ + auto x = crow::json::load(req.body); + if (!x) + return crow::response(400); + int sum = x["a"].i()+x["b"].i(); + std::ostringstream os; + os << sum; + return crow::response{os.str()}; + }); + + // Example of a request taking URL parameters + // If you want to activate all the functions just query + // {ip}:18080/params?foo='blabla'&pew=32&count[]=a&count[]=b + CROW_ROUTE(app, "/params") + ([](const crow::request& req){ + std::ostringstream os; + + // To get a simple string from the url params + // To see it in action /params?foo='blabla' + os << "Params: " << req.url_params << "\n\n"; + os << "The key 'foo' was " << (req.url_params.get("foo") == nullptr ? "not " : "") << "found.\n"; + + // To get a double from the request + // To see in action submit something like '/params?pew=42' + if(req.url_params.get("pew") != nullptr) { + double countD = boost::lexical_cast<double>(req.url_params.get("pew")); + os << "The value of 'pew' is " << countD << '\n'; + } + + // To get a list from the request + // You have to submit something like '/params?count[]=a&count[]=b' to have a list with two values (a and b) + auto count = req.url_params.get_list("count"); + os << "The key 'count' contains " << count.size() << " value(s).\n"; + for(const auto& countVal : count) { + os << " - " << countVal << '\n'; + } + return crow::response{os.str()}; + }); + + CROW_ROUTE(app, "/large") + ([]{ + return std::string(512*1024, ' '); + }); + + // ignore all log + crow::logger::setLogLevel(crow::LogLevel::DEBUG); + + app.port(18080) + .multithreaded() + .run(); +} diff --git a/src/ssl_key_handler.hpp b/src/ssl_key_handler.hpp new file mode 100644 index 0000000..a658d9c --- /dev/null +++ b/src/ssl_key_handler.hpp @@ -0,0 +1,182 @@ +#pragma once + +#include <openssl/bio.h> +#include <openssl/dh.h> +#include <openssl/dsa.h> +#include <openssl/dsa.h> +#include <openssl/err.h> +#include <openssl/evp.h> +#include <openssl/pem.h> +#include <openssl/rand.h> +#include <openssl/rsa.h> +#include <openssl/ssl.h> + +namespace ensuressl +{ +static void init_openssl(void); +static void cleanup_openssl(void); +static EVP_PKEY *create_rsa_key(void); +static void handle_openssl_error(void); + +inline bool verify_openssl_key_cert(const std::string &filepath) +{ + bool private_key_valid = false; + bool cert_valid = false; + FILE *file = fopen(filepath.c_str(), "r"); + if (file != NULL){ + EVP_PKEY *pkey = PEM_read_PrivateKey(file, NULL, NULL, NULL); + int rc; + if (pkey) { + int type = EVP_PKEY_type(pkey->type); + switch (type) { + case EVP_PKEY_RSA: + case EVP_PKEY_RSA2: { + RSA *rsa = EVP_PKEY_get1_RSA(pkey); + rc = RSA_check_key(rsa); + if (rc == 1) { + private_key_valid = true; + } + + //RSA_free(rsa); + + break; + } + default: + break; + } + + if (private_key_valid) { + X509 *x509 = PEM_read_X509(file, NULL, NULL, NULL); + unsigned long err = ERR_get_error(); + + rc = X509_verify(x509, pkey); + err = ERR_get_error(); + if (err == 0 && rc == 1) { + cert_valid = true; + } + } + + EVP_PKEY_free(pkey); + } + fclose(file); + } + return cert_valid; +} + +inline void generate_ssl_certificate(const std::string &filepath) +{ + EVP_PKEY *pPrivKey = NULL; + FILE *pFile = NULL; + init_openssl(); + + pPrivKey = create_rsa_key(); + + // Use this code to directly generate a certificate + X509 *x509; + x509 = X509_new(); + if (x509) { + // TODO get actually random int + ASN1_INTEGER_set(X509_get_serialNumber(x509), 1584); + + // not before this moment + X509_gmtime_adj(X509_get_notBefore(x509), 0); + // Cert is valid for 10 years + X509_gmtime_adj(X509_get_notAfter(x509), 60L * 60L * 24L * 365L * 10L); + + // set the public key to the key we just generated + X509_set_pubkey(x509, pPrivKey); + + // Get the subject name + X509_NAME *name; + name = X509_get_subject_name(x509); + + X509_NAME_add_entry_by_txt(name, "C", MBSTRING_ASC, (unsigned char *)"US", -1, + -1, 0); + X509_NAME_add_entry_by_txt(name, "O", MBSTRING_ASC, + (unsigned char *)"Intel BMC", -1, -1, 0); + X509_NAME_add_entry_by_txt(name, "CN", MBSTRING_ASC, + (unsigned char *)"testhost", -1, -1, 0); + // set the CSR options + X509_set_issuer_name(x509, name); + + // Sign the certificate with our private key + X509_sign(x509, pPrivKey, EVP_sha256()); + + pFile = fopen(filepath.c_str(), "wt"); + + if (pFile) { + PEM_write_PrivateKey(pFile, pPrivKey, NULL, NULL, 0, 0, NULL); + PEM_write_X509(pFile, x509); + fclose(pFile); + pFile = NULL; + } + + X509_free(x509); + } + + if (pPrivKey) { + EVP_PKEY_free(pPrivKey); + pPrivKey = NULL; + } + + //cleanup_openssl(); +} + +EVP_PKEY *create_rsa_key(void) +{ + RSA *pRSA = NULL; + EVP_PKEY *pKey = NULL; + pRSA = RSA_generate_key(2048, RSA_3, NULL, NULL); + pKey = EVP_PKEY_new(); + if (pRSA && pKey && EVP_PKEY_assign_RSA(pKey, pRSA)) { + /* pKey owns pRSA from now */ + if (RSA_check_key(pRSA) <= 0) { + fprintf(stderr, "RSA_check_key failed.\n"); + handle_openssl_error(); + EVP_PKEY_free(pKey); + pKey = NULL; + } + } else { + handle_openssl_error(); + if (pRSA) { + RSA_free(pRSA); + pRSA = NULL; + } + if (pKey) { + EVP_PKEY_free(pKey); + pKey = NULL; + } + } + return pKey; +} + +void init_openssl(void) +{ + if (SSL_library_init()) { + SSL_load_error_strings(); + OpenSSL_add_all_algorithms(); + RAND_load_file("/dev/urandom", 1024); + } else + exit(EXIT_FAILURE); +} + +void cleanup_openssl(void) +{ + CRYPTO_cleanup_all_ex_data(); + ERR_free_strings(); + ERR_remove_thread_state(0); + EVP_cleanup(); +} + +void handle_openssl_error(void) { ERR_print_errors_fp(stderr); } +inline void ensure_openssl_key_present_and_valid(const std::string &filepath) +{ + bool pem_file_valid = false; + + pem_file_valid = verify_openssl_key_cert(filepath); + + if (!pem_file_valid) { + generate_ssl_certificate(filepath); + } +} +}
\ No newline at end of file |

