Ctrl K
ComunidadGuías…

tests/test_request_authorization.py

Rama master · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
#!/usr/bin/env python
# encoding: UTF-8

"""
This file is part of Commix Project (https://commixproject.com).
Copyright (c) 2014-2026 Anastasios Stasinopoulos (@ancst).

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

For more see the file 'readme/COPYING' for copying permission.
"""

import os
import base64
import shutil
import socket
import tempfile
import unittest

from tests._testutils import stage
from src.utils import settings
from src.core.parse import cmdline as menu
from src.core.parse import request

CREDENTIALS = "user:pw"
ENCODED = base64.b64encode(CREDENTIALS.encode()).decode()

"""
Fail closed: a captured request is read before anything is sent, so a test of that reading which
reaches for the network is a broken test rather than a slow one.
"""
def _no_transport(*args, **kwargs):
  raise RuntimeError("Reading a captured request is exercised offline; no transport may be opened.")

class _Captured(unittest.TestCase):
  def setUp(self):
    self.saved_sockets = (socket.socket, socket.create_connection, socket.getaddrinfo)
    socket.socket, socket.create_connection, socket.getaddrinfo = (_no_transport,) * 3
    self.saved_options = dict(vars(menu.options))
    self.saved_command_line = dict(request._command_line_options)
    menu.options.scope = None
    request._command_line_options.clear()
    self.directory = tempfile.mkdtemp(prefix="commix-auth-")

  def tearDown(self):
    socket.socket, socket.create_connection, socket.getaddrinfo = self.saved_sockets
    vars(menu.options).clear()
    vars(menu.options).update(self.saved_options)
    request._command_line_options.clear()
    request._command_line_options.update(self.saved_command_line)
    shutil.rmtree(self.directory, ignore_errors=True)

  def parse(self, *headers):
    path = os.path.join(self.directory, "captured.invalid.txt")
    raw = "GET /review?x=1 HTTP/1.1\n" + "".join(line + "\n" for line in headers) + "\n"
    with open(path, "w", encoding=settings.DEFAULT_CODEC) as handle:
      handle.write(raw)
    return request.parse_requests(path)[0]

class AuthorizationField(_Captured):
  """
  The 'Authorization' field of a captured request, read the way every other known field is.

  Matched anywhere in the line rather than at its start, as it was, the name was found inside
  'X-Authorization' too - so another header's credentials were adopted as the ones to authenticate
  with, and that header never reached the request, since what is read here is not kept as an extra.
  """
  def test_the_credentials_are_read_however_the_colon_is_spaced(self):
    for line in ("Authorization: Basic " + ENCODED,
                 "Authorization:Basic " + ENCODED,
                 "Authorization:\tBasic " + ENCODED,
                 "authorization:  Basic " + ENCODED):
      with self.subTest(line=line):
        target = self.parse("Host: asset.invalid", line)
        self.assertEqual("basic", target["auth_type"])
        self.assertEqual(CREDENTIALS, target["auth_cred"])

  def test_a_field_that_merely_ends_in_the_name_is_not_the_field(self):
    for name in ("X-Authorization", "Proxy-Authorization", "My-Authorization"):
      with self.subTest(name=name):
        target = self.parse("Host: asset.invalid", name + ": Basic " + ENCODED)
        self.assertIsNone(target["auth_type"], name + " was taken for the authorization field")
        self.assertIsNone(target["auth_cred"])

  def test_such_a_field_still_reaches_the_request_as_an_extra_header(self):
    target = self.parse("Host: asset.invalid", "X-Authorization: Basic " + ENCODED, "X-Trace: keepme")
    self.assertIn("X-Authorization", target["headers"] or "")
    self.assertIn("X-Trace", target["headers"] or "")

  def test_the_field_itself_is_consumed_rather_than_sent_again(self):
    target = self.parse("Host: asset.invalid", "Authorization: Basic " + ENCODED, "X-Trace: keepme")
    self.assertNotIn("Authorization", target["headers"] or "")
    self.assertIn("X-Trace", target["headers"] or "")

if __name__ == "__main__":
  unittest.main()