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.rest;
019
020import static org.hamcrest.CoreMatchers.not;
021import static org.hamcrest.MatcherAssert.assertThat;
022import static org.hamcrest.core.Is.is;
023import static org.hamcrest.core.IsEqual.equalTo;
024
025import org.apache.hadoop.hbase.HBaseTestingUtil;
026import org.apache.hadoop.hbase.rest.client.Client;
027import org.apache.hadoop.hbase.rest.client.Cluster;
028import org.apache.hadoop.hbase.rest.client.Response;
029import org.apache.hadoop.hbase.testclassification.MediumTests;
030import org.apache.hadoop.hbase.testclassification.RestTests;
031import org.junit.jupiter.api.AfterEach;
032import org.junit.jupiter.api.Tag;
033import org.junit.jupiter.api.Test;
034
035@Tag(RestTests.TAG)
036@Tag(MediumTests.TAG)
037public class TestSecurityHeadersFilter {
038
039  private static final HBaseTestingUtil TEST_UTIL = new HBaseTestingUtil();
040  private static final HBaseRESTTestingUtility REST_TEST_UTIL = new HBaseRESTTestingUtility();
041  private static Client client;
042
043  @AfterEach
044  public void tearDown() throws Exception {
045    REST_TEST_UTIL.shutdownServletContainer();
046    TEST_UTIL.shutdownMiniCluster();
047  }
048
049  @Test
050  public void testDefaultValues() throws Exception {
051    TEST_UTIL.startMiniCluster();
052    REST_TEST_UTIL.startServletContainer(TEST_UTIL.getConfiguration());
053    client = new Client(new Cluster().add("localhost", REST_TEST_UTIL.getServletPort()));
054
055    String path = "/version/cluster";
056    Response response = client.get(path);
057    assertThat(response.getCode(), equalTo(200));
058
059    assertThat("Header 'X-Content-Type-Options' is missing from Rest response",
060      response.getHeader("X-Content-Type-Options"), is(not((String) null)));
061    assertThat("Header 'X-Content-Type-Options' has invalid default value",
062      response.getHeader("X-Content-Type-Options"), equalTo("nosniff"));
063
064    assertThat("Header 'X-XSS-Protection' is missing from Rest response",
065      response.getHeader("X-XSS-Protection"), is(not((String) null)));
066    assertThat("Header 'X-XSS-Protection' has invalid default value",
067      response.getHeader("X-XSS-Protection"), equalTo("1; mode=block"));
068
069    assertThat("Header 'Strict-Transport-Security' should be missing from Rest response,"
070      + "but it's present", response.getHeader("Strict-Transport-Security"), is((String) null));
071    assertThat(
072      "Header 'Content-Security-Policy' should be missing from Rest response," + "but it's present",
073      response.getHeader("Content-Security-Policy"), is((String) null));
074  }
075
076  @Test
077  public void testHstsAndCspSettings() throws Exception {
078    TEST_UTIL.getConfiguration().set("hbase.http.filter.hsts.value",
079      "max-age=63072000;includeSubDomains;preload");
080    TEST_UTIL.getConfiguration().set("hbase.http.filter.csp.value",
081      "default-src https: data: 'unsafe-inline' 'unsafe-eval'");
082    TEST_UTIL.startMiniCluster();
083    REST_TEST_UTIL.startServletContainer(TEST_UTIL.getConfiguration());
084    client = new Client(new Cluster().add("localhost", REST_TEST_UTIL.getServletPort()));
085
086    String path = "/version/cluster";
087    Response response = client.get(path);
088    assertThat(response.getCode(), equalTo(200));
089
090    assertThat("Header 'Strict-Transport-Security' is missing from Rest response",
091      response.getHeader("Strict-Transport-Security"), is(not((String) null)));
092    assertThat("Header 'Strict-Transport-Security' has invalid value",
093      response.getHeader("Strict-Transport-Security"),
094      equalTo("max-age=63072000;includeSubDomains;preload"));
095
096    assertThat("Header 'Content-Security-Policy' is missing from Rest response",
097      response.getHeader("Content-Security-Policy"), is(not((String) null)));
098    assertThat("Header 'Content-Security-Policy' has invalid value",
099      response.getHeader("Content-Security-Policy"),
100      equalTo("default-src https: data: 'unsafe-inline' 'unsafe-eval'"));
101  }
102}