blob: 4fa3003e719cb64b9ea12100aa3571d5e36aff5a [file] [log] [blame]
Ed Tanous9140a672017-04-24 17:01:32 -07001#include <crow/app.h>
Ed Tanous1abe55e2018-09-05 08:30:59 -07002
3#include <security_headers_middleware.hpp>
4
Ed Tanous9140a672017-04-24 17:01:32 -07005#include <gmock/gmock.h>
Ed Tanous55c7b7a2018-05-22 15:27:24 -07006#include <gtest/gtest.h>
Ed Tanousb4a7bfa2017-04-04 17:23:00 -07007
8using namespace crow;
9using namespace std;
10
11// Tests that the security headers are added correctly
Ed Tanous1abe55e2018-09-05 08:30:59 -070012TEST(SecurityHeaders, TestHeadersExist)
13{
14 App<SecurityHeadersMiddleware> app;
15 app.bindaddr("127.0.0.1").port(45451);
16 BMCWEB_ROUTE(app, "/")([]() { return boost::beast::http::status::ok; });
17 auto _ = async(launch::async, [&] { app.run(); });
Ed Tanousb4a7bfa2017-04-04 17:23:00 -070018
Ed Tanous8f626352018-12-19 14:51:54 -080019 asio::io_context is;
Ed Tanous1abe55e2018-09-05 08:30:59 -070020 std::array<char, 2048> buf;
21 std::string sendmsg;
Ed Tanousb4a7bfa2017-04-04 17:23:00 -070022
Ed Tanous1abe55e2018-09-05 08:30:59 -070023 {
24 // Retry a couple of times waiting for the server to come up
25 // TODO(ed) This is really unfortunate, and should use some form of
26 // mock
27 asio::ip::tcp::socket c(is);
28 for (int i = 0; i < 200; i++)
29 {
30 try
31 {
32 c.connect(asio::ip::tcp::endpoint(
33 asio::ip::address::from_string("127.0.0.1"), 45451));
34 c.close();
35 break;
36 }
37 catch (std::exception e)
38 {
39 // do nothing. We expect this to fail while the server is
40 // starting up
41 }
42 }
43 }
44
45 // Test correct login credentials
46 sendmsg = "GET /\r\n\r\n";
47
Ed Tanousb4a7bfa2017-04-04 17:23:00 -070048 asio::ip::tcp::socket c(is);
Ed Tanous1abe55e2018-09-05 08:30:59 -070049 c.connect(asio::ip::tcp::endpoint(
50 asio::ip::address::from_string("127.0.0.1"), 45451));
51 c.send(asio::buffer(sendmsg));
52 c.receive(asio::buffer(buf));
53 c.close();
54 auto return_code = std::string(&buf[9], &buf[12]);
55 EXPECT_EQ("200", return_code);
56 std::string response(std::begin(buf), std::end(buf));
57
58 // This is a routine to split strings until a blank is hit
59 // TODO(ed) this should really use the HTTP parser
60 std::vector<std::string> headers;
61 std::string::size_type pos = 0;
62 std::string::size_type prev = 0;
63 while ((pos = response.find("\r\n", prev)) != std::string::npos)
64 {
65 auto this_string = response.substr(prev, pos - prev);
66 if (this_string == "")
67 {
68 break;
69 }
70 headers.push_back(this_string);
71 prev = pos + 2;
Ed Tanousb4a7bfa2017-04-04 17:23:00 -070072 }
Ed Tanous1abe55e2018-09-05 08:30:59 -070073 headers.push_back(response.substr(prev));
Ed Tanousb4a7bfa2017-04-04 17:23:00 -070074
Ed Tanous1abe55e2018-09-05 08:30:59 -070075 EXPECT_EQ(headers[0], "HTTP/1.1 200 OK");
76 EXPECT_THAT(headers, ::testing::Contains("Strict-Transport-Security: "
77 "max-age=31536000; "
78 "includeSubdomains; preload"));
79 EXPECT_THAT(headers, ::testing::Contains("X-UA-Compatible: IE=11"));
80 EXPECT_THAT(headers, ::testing::Contains("X-Frame-Options: DENY"));
81 EXPECT_THAT(headers,
82 ::testing::Contains("X-XSS-Protection: 1; mode=block"));
83 EXPECT_THAT(headers, ::testing::Contains(
84 "X-Content-Security-Policy: default-src 'self'"));
85 app.stop();
Ed Tanousb4a7bfa2017-04-04 17:23:00 -070086}