Esempio n. 1
0
    def __call__(self, environ, start_response):
        self.environ = environ
        self.start_response = start_response

        try:
            self.full_uri = environ['SCRIPT_URI']
            self.path = environ['SCRIPT_URL'][len(environ['SCRIPT_NAME']):]
            self.host = environ['wsgi.url_scheme'] + "://" + environ[
                'SERVER_NAME']
        except:
            self.full_uri = environ['REQUEST_URI']
            self.path = environ['PATH_INFO']
            self.host = environ['HTTP_HOST']

        if environ['QUERY_STRING']:
            #self.query = urlparse.parse_qs(environ['QUERY_STRING'])
            self.query = parse_qs(environ['QUERY_STRING'])
        else:
            self.query = {}

        try:
            self.body = environ['wsgi.input'].read()
        except:
            self.body = ''

        h = {}
        for (k, v) in environ.items():
            if k.startswith('HTTP_'):
                name = k[5:].lower().replace('_', '-')
                h[name] = v
        self.in_headers = h

        self.status = 200
        self.out_headers = headers.Headers([])

        try:
            data = self.handle()
        except:
            sio = StringIO.StringIO()
            cgitb.Hook(file=sio).handle()
            sio.seek(0)
            data = sio.read()
            self.out_headers['Content-type'] = 'text/html'
            self.status = 500

        self.out_headers['Content-length'] = str(len(data))
        status = "%s %s" % (self.status, self.codes[self.status])
        start_response(status, self.out_headers.items())

        if type(data) == str:
            return [data]
        elif type(data) == unicode:
            return [data.encode('utf-8')]
        else:
            # see if response is iterable
            try:
                iter(data)
                return data
            except TypeError:
                return [data]
Esempio n. 2
0
    def __init__(self,
                 http_method=None,
                 service_path=None,
                 headers=None,
                 **kwargs):
        """Constructor.

    Args:
      Same as RequestState, including:
        http_method: Assigned to property.
        service_path: Assigned to property.
        headers: HTTP request headers.  If instance of Headers, assigned to
          property without copying.  If dict, will convert to name value pairs
          for use with Headers constructor.  Otherwise, passed as parameters to
          Headers constructor.
    """
        super(HttpRequestState, self).__init__(**kwargs)

        self.__http_method = http_method
        self.__service_path = service_path

        # Initialize headers.
        if isinstance(headers, dict):
            header_list = []
            for key, value in sorted(headers.items()):
                if not isinstance(value, list):
                    value = [value]
                for item in value:
                    header_list.append((key, item))
                headers = header_list
        self.__headers = wsgi_headers.Headers(headers or [])
Esempio n. 3
0
 def __init__(self, uri):
     """Set up various useful defaults."""
     self._headers = []
     self.headers = headers.Headers(self._headers)
     guess = mimetypes.guess_type(uri)[0]
     self.headers['Content-Type'] = guess or 'text/html'
     self.status = '200 OK'
     self.body = ""
Esempio n. 4
0
        def CspStartResponse(status, headers, exc_info=None):
            """Add the CSP header to the response. Signature determined by WSGI."""
            # If the headers are given to us as a list or a dict, convert that to a
            # Headers object which can correctly support duplicate headers.
            if isinstance(headers, list):
                headers = wsgi_headers.Headers(headers)
            elif isinstance(headers, dict):
                headers = wsgi_headers.Headers(list(headers.items()))
            # Set CSP header if CSP is enabled.
            if csp_enabled:
                headers.add_header(csp_header_key, csp_directives)
            # Set Trusted Types CSP header if Trusted Types are enabled.
            if tt_enabled:
                headers.add_header(tt_header_key, tt_directives)

            # Pass the headers to the next middleware as a List[Tuple[str, str]] since
            # gunicorn needs them in that format.
            return start_response(status, headers.items(), exc_info)
Esempio n. 5
0
 def __init__(self, connection):
     self._connection = connection
     self.headers = headers.Headers([('Transfer-Encoding', 'chunked')])
     self.out = OutFile(self._connection)
Esempio n. 6
0
class CspTest(parameterized.TestCase, test_lib.GRRBaseTest):
  """Tests for Csp."""

  def testGetCspHeaderKey(self):
    enforced_result = csp.GetCspHeaderKey(False)
    report_only_result = csp.GetCspHeaderKey(True)
    self.assertEqual(csp.HEADER_KEY_ENFORCE, enforced_result)
    self.assertEqual(csp.HEADER_KEY_REPORT_ONLY, report_only_result)

  def testBuildPolicy(self):
    expected_directives = [
        "upgrade-insecure-requests", "default-src 'self'", "base-uri 'none'",
        "object-src 'none'", "img-src 'self' https: data:"
    ]

    result = csp.BuildPolicy(test_policy)
    result_directives = [x.strip() for x in result.split(";")]
    self.assertCountEqual(expected_directives, result_directives)

  @parameterized.named_parameters(
      dict(
          testcase_name="Disable CSP",
          csp_enabled=False,
          csp_report_only=False,
          tt_enabled=False,
          tt_report_only=False,
          expected_headers=[]),
      dict(
          testcase_name="Enable enforced Trusted Types, with an existing CSP header",
          csp_enabled=False,
          csp_report_only=True,
          tt_enabled=True,
          tt_report_only=False,
          existing_headers=[(csp.HEADER_KEY_ENFORCE, "existing policy")],
          expected_headers=[(csp.HEADER_KEY_ENFORCE, "existing policy"),
                            (csp.HEADER_KEY_ENFORCE,
                             "require-trusted-types-for 'script'")]),
      dict(
          testcase_name="Enable enforced CSP, with custom policy",
          csp_enabled=True,
          csp_policy='{"frame-ancestors": ["\'self\'"], "foo": ["bar"]}',
          csp_report_only=False,
          tt_enabled=False,
          expected_headers=[(csp.HEADER_KEY_ENFORCE,
                             "frame-ancestors 'self'; foo bar")]),
      dict(
          testcase_name="Enable enforced CSP & trusted types, with custom policy",
          csp_enabled=True,
          csp_policy='{"frame-ancestors": ["\'self\'"], "foo": ["bar"]}',
          csp_report_only=False,
          tt_enabled=True,
          tt_report_only=False,
          expected_headers=[
              (csp.HEADER_KEY_ENFORCE, "frame-ancestors 'self'; foo bar"),
              (csp.HEADER_KEY_ENFORCE, "require-trusted-types-for 'script'")
          ]),
      dict(
          testcase_name="Enable report-only CSP, no trusted types, with report URL",
          csp_enabled=True,
          csp_report_only=True,
          tt_enabled=False,
          report_uri="test",
          expected_headers=[(csp.HEADER_KEY_REPORT_ONLY, "report-uri test")]),
      dict(
          testcase_name="Enable report-only trusted types",
          csp_enabled=False,
          csp_report_only=False,
          tt_enabled=True,
          tt_report_only=True,
          expected_headers=[(csp.HEADER_KEY_REPORT_ONLY,
                             "require-trusted-types-for 'script'")]),
      dict(
          testcase_name="Enable report-only trusted types with report URL",
          csp_enabled=False,
          csp_report_only=False,
          tt_enabled=True,
          tt_report_only=True,
          report_uri="test",
          expected_headers=[
              (csp.HEADER_KEY_REPORT_ONLY,
               "require-trusted-types-for 'script'; report-uri test")
          ]),
      dict(
          testcase_name="Set headers for URLs in the include list",
          csp_enabled=True,
          csp_report_only=False,
          csp_policy='{"frame-ancestors": ["\'self\'"], "foo": ["bar"]}',
          tt_enabled=True,
          tt_report_only=True,
          url_path="/v2/page.html",
          include_prefixes=["/v2"],
          expected_headers=[
              (csp.HEADER_KEY_ENFORCE, "frame-ancestors 'self'; foo bar"),
              (csp.HEADER_KEY_REPORT_ONLY, "require-trusted-types-for 'script'")
          ]),
      dict(
          testcase_name="Don't set headers for URLs not in the include list",
          csp_enabled=True,
          tt_enabled=True,
          url_path="/v1/page.html",
          include_prefixes=["/v2"],
          expected_headers=[]),
      dict(
          testcase_name="Don't set headers for URLs in the exclude list",
          csp_enabled=True,
          tt_enabled=True,
          url_path="/v1/page.html",
          exclude_prefixes=["/v1"],
          expected_headers=[]),
      dict(
          testcase_name="Handle specifying both an include and exclude list",
          csp_enabled=True,
          tt_enabled=True,
          url_path="/v2/not-this-one.html",
          include_prefixes=["/v2"],
          exclude_prefixes=["/v2/not-this-one.html"],
          expected_headers=[]),
      dict(
          testcase_name="Handle duplicate headers as a list",
          csp_enabled=False,
          tt_enabled=True,
          existing_headers=[("Set-Cookie", "foo=bar"),
                            ("Set-Cookie", "bin=baz")],
          expected_headers=[
              ("Set-Cookie", "foo=bar"), ("Set-Cookie", "bin=baz"),
              (csp.HEADER_KEY_REPORT_ONLY, "require-trusted-types-for 'script'")
          ]),
      dict(
          testcase_name="Handle duplicate headers as wsgi headers",
          csp_enabled=False,
          tt_enabled=True,
          existing_headers=wsgi.Headers([("Set-Cookie", "foo=bar"),
                                         ("Set-Cookie", "bin=baz")]),
          expected_headers=[
              ("Set-Cookie", "foo=bar"), ("Set-Cookie", "bin=baz"),
              (csp.HEADER_KEY_REPORT_ONLY, "require-trusted-types-for 'script'")
          ]),
      dict(
          testcase_name="Handle headers as a dict",
          csp_enabled=False,
          tt_enabled=True,
          existing_headers={"Set-Cookie": "foo=bar"},
          expected_headers=[("Set-Cookie", "foo=bar"),
                            (csp.HEADER_KEY_REPORT_ONLY,
                             "require-trusted-types-for 'script'")]),
      dict(
          testcase_name="Raise an exception if multiple report URIs are given",
          csp_enabled=True,
          tt_enabled=False,
          csp_policy='{"report-uri": ["test"], "foo": ["bar"]}',
          report_uri="test",
          expected_exception=RuntimeError),
  )
  def testCspMiddleware(self,
                        csp_enabled=False,
                        csp_policy="{}",
                        csp_report_only=True,
                        tt_enabled=False,
                        tt_report_only=True,
                        report_uri="",
                        include_prefixes=(),
                        exclude_prefixes=(),
                        url_path="",
                        existing_headers=(),
                        expected_headers=(),
                        expected_exception=None):
    """Test if CSP headers are correctly set."""
    expected_output = "Response successfully processed"
    environ_stub = {"PATH_INFO": url_path}

    def ApplicationStub(unused_environ, start_response):
      return start_response(200, existing_headers or [])

    def StartResponseMock(unused_status, headers, unused_exc_info=None):
      """This mock is called at the end of CspStartResponse."""
      self.assertEqual(headers, expected_headers)
      return expected_output

    with test_lib.ConfigOverrider({
        "AdminUI.csp_enabled": csp_enabled,
        "AdminUI.csp_policy": csp_policy,
        "AdminUI.csp_report_only": csp_report_only,
        "AdminUI.trusted_types_enabled": tt_enabled,
        "AdminUI.trusted_types_report_only": tt_report_only,
        "AdminUI.csp_report_uri": report_uri,
        "AdminUI.csp_include_url_prefixes": include_prefixes,
        "AdminUI.csp_exclude_url_prefixes": exclude_prefixes
    }):
      if expected_exception:
        with self.assertRaises(expected_exception):
          csp.CspMiddleware(ApplicationStub)
      else:
        test_app = csp.CspMiddleware(ApplicationStub)
        output = test_app(environ_stub, StartResponseMock)

        self.assertEqual(expected_output, output)