| Ed Tanous | b4a7bfa | 2017-04-04 17:23:00 -0700 | [diff] [blame] | 1 | #include <security_headers_middleware.hpp> | 
| Ed Tanous | 9140a67 | 2017-04-24 17:01:32 -0700 | [diff] [blame^] | 2 | #include <crow/app.h> | 
|  | 3 | #include <gtest/gtest.h> | 
|  | 4 | #include <gmock/gmock.h> | 
| Ed Tanous | b4a7bfa | 2017-04-04 17:23:00 -0700 | [diff] [blame] | 5 |  | 
|  | 6 | using namespace crow; | 
|  | 7 | using namespace std; | 
|  | 8 |  | 
|  | 9 | // Tests that the security headers are added correctly | 
|  | 10 | TEST(SecurityHeaders, TestHeadersExist) { | 
|  | 11 | App<SecurityHeadersMiddleware> app; | 
|  | 12 | app.bindaddr("127.0.0.1").port(45451); | 
|  | 13 | CROW_ROUTE(app, "/")([]() { return 200; }); | 
|  | 14 | auto _ = async(launch::async, [&] { app.run(); }); | 
|  | 15 |  | 
|  | 16 | asio::io_service is; | 
|  | 17 | std::array<char, 2048> buf; | 
|  | 18 | std::string sendmsg; | 
|  | 19 |  | 
|  | 20 | { | 
|  | 21 | // Retry a couple of times waiting for the server to come up | 
|  | 22 | // TODO(ed)  This is really unfortunate, and should use some form of mock | 
|  | 23 | asio::ip::tcp::socket c(is); | 
|  | 24 | for (int i = 0; i < 200; i++) { | 
|  | 25 | try { | 
|  | 26 | c.connect(asio::ip::tcp::endpoint( | 
|  | 27 | asio::ip::address::from_string("127.0.0.1"), 45451)); | 
|  | 28 | c.close(); | 
|  | 29 | break; | 
|  | 30 | } catch (std::exception e) { | 
|  | 31 | // do nothing.  We expect this to fail while the server is starting up | 
|  | 32 | } | 
|  | 33 | } | 
|  | 34 | } | 
|  | 35 |  | 
|  | 36 | // Test correct login credentials | 
|  | 37 | sendmsg = "GET /\r\n\r\n"; | 
|  | 38 |  | 
|  | 39 | asio::ip::tcp::socket c(is); | 
|  | 40 | c.connect(asio::ip::tcp::endpoint(asio::ip::address::from_string("127.0.0.1"), | 
|  | 41 | 45451)); | 
|  | 42 | c.send(asio::buffer(sendmsg)); | 
| Ed Tanous | 7d3dba4 | 2017-04-05 13:04:39 -0700 | [diff] [blame] | 43 | c.receive(asio::buffer(buf)); | 
| Ed Tanous | b4a7bfa | 2017-04-04 17:23:00 -0700 | [diff] [blame] | 44 | c.close(); | 
|  | 45 | auto return_code = std::string(&buf[9], &buf[12]); | 
|  | 46 | EXPECT_EQ("200", return_code); | 
|  | 47 | std::string response(std::begin(buf), std::end(buf)); | 
|  | 48 |  | 
| Ed Tanous | 7d3dba4 | 2017-04-05 13:04:39 -0700 | [diff] [blame] | 49 | // This is a routine to split strings until a blank is hit | 
| Ed Tanous | b4a7bfa | 2017-04-04 17:23:00 -0700 | [diff] [blame] | 50 | // TODO(ed) this should really use the HTTP parser | 
|  | 51 | std::vector<std::string> headers; | 
|  | 52 | std::string::size_type pos = 0; | 
|  | 53 | std::string::size_type prev = 0; | 
|  | 54 | while ((pos = response.find("\r\n", prev)) != std::string::npos) { | 
|  | 55 | auto this_string = response.substr(prev, pos - prev); | 
|  | 56 | if (this_string == "") { | 
|  | 57 | break; | 
|  | 58 | } | 
|  | 59 | headers.push_back(this_string); | 
|  | 60 | prev = pos + 2; | 
|  | 61 | } | 
|  | 62 | headers.push_back(response.substr(prev)); | 
|  | 63 |  | 
|  | 64 | EXPECT_EQ(headers[0], "HTTP/1.1 200 OK"); | 
|  | 65 | EXPECT_THAT(headers, ::testing::Contains("Strict-Transport-Security: " | 
|  | 66 | "max-age=31536000; " | 
|  | 67 | "includeSubdomains; preload")); | 
|  | 68 | EXPECT_THAT(headers, ::testing::Contains("X-UA-Compatible: IE=11")); | 
|  | 69 | EXPECT_THAT(headers, ::testing::Contains("X-Frame-Options: DENY")); | 
|  | 70 | EXPECT_THAT(headers, ::testing::Contains("X-XSS-Protection: 1; mode=block")); | 
|  | 71 | EXPECT_THAT(headers, ::testing::Contains( | 
|  | 72 | "X-Content-Security-Policy: default-src 'self'")); | 
|  | 73 | app.stop(); | 
|  | 74 | } |