blob: e7008cb165178c61e24dfd3ca82b89d7336d6f9a [file] [log] [blame]
Ed Tanousb4a7bfa2017-04-04 17:23:00 -07001#include <security_headers_middleware.hpp>
Ed Tanous9140a672017-04-24 17:01:32 -07002#include <crow/app.h>
Ed Tanous9140a672017-04-24 17:01:32 -07003#include <gmock/gmock.h>
Ed Tanous55c7b7a2018-05-22 15:27:24 -07004#include <gtest/gtest.h>
Ed Tanousb4a7bfa2017-04-04 17:23:00 -07005
6using namespace crow;
7using namespace std;
8
9// Tests that the security headers are added correctly
10TEST(SecurityHeaders, TestHeadersExist) {
11 App<SecurityHeadersMiddleware> app;
12 app.bindaddr("127.0.0.1").port(45451);
Ed Tanous55c7b7a2018-05-22 15:27:24 -070013 BMCWEB_ROUTE(app, "/")([]() { return boost::beast::http::status::ok; });
Ed Tanousb4a7bfa2017-04-04 17:23:00 -070014 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 Tanous7d3dba42017-04-05 13:04:39 -070043 c.receive(asio::buffer(buf));
Ed Tanousb4a7bfa2017-04-04 17:23:00 -070044 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 Tanous7d3dba42017-04-05 13:04:39 -070049 // This is a routine to split strings until a blank is hit
Ed Tanousb4a7bfa2017-04-04 17:23:00 -070050 // 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}