001/**
002 * Licensed to the Apache Software Foundation (ASF) under one
003 * or more contributor license agreements.  See the NOTICE file
004 * distributed with this work for additional information
005 * regarding copyright ownership.  The ASF licenses this file
006 * to you under the Apache License, Version 2.0 (the
007 * "License"); you may not use this file except in compliance
008 * with the License.  You may obtain a copy of the License at
009 *
010 *     http://www.apache.org/licenses/LICENSE-2.0
011 *
012 * Unless required by applicable law or agreed to in writing, software
013 * distributed under the License is distributed on an "AS IS" BASIS,
014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015 * See the License for the specific language governing permissions and
016 * limitations under the License.
017 */
018package org.apache.hadoop.hbase.http;
019
020import static org.apache.hadoop.hbase.http.HttpServerFunctionalTest.createTestServer;
021import static org.apache.hadoop.hbase.http.HttpServerFunctionalTest.getServerURL;
022import static org.hamcrest.CoreMatchers.equalTo;
023import static org.hamcrest.CoreMatchers.is;
024import static org.hamcrest.CoreMatchers.not;
025import static org.hamcrest.MatcherAssert.assertThat;
026
027import java.io.IOException;
028import java.net.HttpURLConnection;
029import java.net.URL;
030import org.apache.hadoop.conf.Configuration;
031import org.apache.hadoop.hbase.HBaseClassTestRule;
032import org.apache.hadoop.hbase.testclassification.MediumTests;
033import org.hamcrest.core.Is;
034import org.hamcrest.core.IsEqual;
035import org.junit.After;
036import org.junit.ClassRule;
037import org.junit.Test;
038import org.junit.experimental.categories.Category;
039
040@Category({HttpServerFunctionalTest.class, MediumTests.class})
041public class TestSecurityHeadersFilter {
042  private static URL baseUrl;
043  private HttpServer http;
044
045  @ClassRule
046  public static final HBaseClassTestRule CLASS_RULE =
047      HBaseClassTestRule.forClass(TestSecurityHeadersFilter.class);
048
049  @After
050  public void tearDown() throws Exception {
051    http.stop();
052  }
053
054  @Test
055  public void testDefaultValues() throws Exception {
056    http = createTestServer();
057    http.start();
058    baseUrl = getServerURL(http);
059
060    URL url = new URL(baseUrl, "/");
061    HttpURLConnection conn = (HttpURLConnection) url.openConnection();
062    assertThat(conn.getResponseCode(), equalTo(HttpURLConnection.HTTP_OK));
063
064    assertThat("Header 'X-Content-Type-Options' is missing",
065        conn.getHeaderField("X-Content-Type-Options"), is(not((String)null)));
066    assertThat(conn.getHeaderField("X-Content-Type-Options"), equalTo("nosniff"));
067    assertThat("Header 'X-XSS-Protection' is missing",
068        conn.getHeaderField("X-XSS-Protection"), is(not((String)null)));
069    assertThat("Header 'X-XSS-Protection' has invalid value",
070        conn.getHeaderField("X-XSS-Protection"), equalTo("1; mode=block"));
071
072    assertThat("Header 'Strict-Transport-Security' should be missing from response," +
073            "but it's present",
074        conn.getHeaderField("Strict-Transport-Security"), is((String)null));
075    assertThat("Header 'Content-Security-Policy' should be missing from response," +
076            "but it's present",
077        conn.getHeaderField("Content-Security-Policy"), is((String)null));
078  }
079
080  @Test
081  public void testHstsAndCspSettings() throws IOException {
082    Configuration conf = new Configuration();
083    conf.set("hbase.http.filter.hsts.value",
084        "max-age=63072000;includeSubDomains;preload");
085    conf.set("hbase.http.filter.csp.value",
086        "default-src https: data: 'unsafe-inline' 'unsafe-eval'");
087    http = createTestServer(conf);
088    http.start();
089    baseUrl = getServerURL(http);
090
091    URL url = new URL(baseUrl, "/");
092    HttpURLConnection conn = (HttpURLConnection) url.openConnection();
093    assertThat(conn.getResponseCode(), equalTo(HttpURLConnection.HTTP_OK));
094
095    assertThat("Header 'Strict-Transport-Security' is missing from Rest response",
096        conn.getHeaderField("Strict-Transport-Security"), Is.is(not((String)null)));
097    assertThat("Header 'Strict-Transport-Security' has invalid value",
098        conn.getHeaderField("Strict-Transport-Security"),
099        IsEqual.equalTo("max-age=63072000;includeSubDomains;preload"));
100
101    assertThat("Header 'Content-Security-Policy' is missing from Rest response",
102        conn.getHeaderField("Content-Security-Policy"), Is.is(not((String)null)));
103    assertThat("Header 'Content-Security-Policy' has invalid value",
104        conn.getHeaderField("Content-Security-Policy"),
105        IsEqual.equalTo("default-src https: data: 'unsafe-inline' 'unsafe-eval'"));
106  }
107}