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