# Path: notifications_utils/request_helper.py
# class NotifyRequest(Request):
#     """
#         A custom Request class, implementing extraction of zipkin headers used to trace request through cloudfoundry
#         as described here: https://docs.cloudfoundry.org/concepts/http-routing.html#zipkin-headers
#     """
# 
#     @property
#     def request_id(self):
#         return self.trace_id
# 
#     @property
#     def trace_id(self):
#         """
#             The "trace id" (in zipkin terms) assigned to this request, if present (None otherwise)
#         """
#         if not hasattr(self, "_trace_id"):
#             self._trace_id = self._get_header_value(current_app.config['NOTIFY_TRACE_ID_HEADER'])
#         return self._trace_id
# 
#     @property
#     def span_id(self):
#         """
#             The "span id" (in zipkin terms) set in this request's header, if present (None otherwise)
#         """
#         if not hasattr(self, "_span_id"):
#             # note how we don't generate an id of our own. not being supplied a span id implies that we are running in
#             # an environment with no span-id-aware request router, and thus would have no intermediary to prevent the
#             # propagation of our span id all the way through all our onwards requests much like trace id. and the point
#             # of span id is to assign identifiers to each individual request.
#             self._span_id = self._get_header_value(current_app.config['NOTIFY_SPAN_ID_HEADER'])
#         return self._span_id
# 
#     @property
#     def parent_span_id(self):
#         """
#             The "parent span id" (in zipkin terms) set in this request's header, if present (None otherwise)
#         """
#         if not hasattr(self, "_parent_span_id"):
#             self._parent_span_id = self._get_header_value(current_app.config['NOTIFY_PARENT_SPAN_ID_HEADER'])
#         return self._parent_span_id
# 
#     def _get_header_value(self, header_name):
#         """
#         Returns value of the given header
#         """
#         if header_name in self.headers and self.headers[header_name]:
#             return self.headers[header_name]
# 
#         return None
# 
# def _check_proxy_header_secret(request, secrets, header='X-Custom-Forwarder'):
#     if header not in request.headers:
#         return False, "Header missing"
# 
#     header_secret = request.headers.get(header)
#     if not header_secret:
#         return False, "Header exists but is empty"
# 
#     # if there isn't any non-empty secret configured we fail closed
#     if not any(secrets):
#         return False, "Secrets are not configured"
# 
#     for i, secret in enumerate(secrets):
#         if header_secret == secret:
#             return True, "Key used: {}".format(i + 1)  # add 1 to make it human-compatible
# 
#     return False, "Header didn't match any keys"


from unittest import mock  # noqa
from werkzeug.test import EnvironBuilder
from notifications_utils.request_helper import (
    NotifyRequest,
    _check_proxy_header_secret,
)
import pytest




@pytest.mark.parametrize('header,secrets,expected', [
    ({'X-Custom-Forwarder': 'right_key'}, ['right_key', 'old_key'], (True, 'Key used: 1')),
    ({'X-Custom-Forwarder': 'right_key'}, ['right_key'], (True, 'Key used: 1')),
    ({'X-Custom-Forwarder': 'right_key'}, ['right_key', ''], (True, 'Key used: 1')),
    ({'My-New-Header': 'right_key'}, ['right_key', ''], (True, 'Key used: 1')),
    ({'X-Custom-Forwarder': 'right_key'}, ['', 'right_key'], (True, 'Key used: 2')),
    ({'X-Custom-Forwarder': 'right_key'}, ['', 'old_key', 'right_key'], (True, 'Key used: 3')),
    ({'X-Custom-Forwarder': ''}, ['right_key', 'old_key'], (False, 'Header exists but is empty')),
    ({'X-Custom-Forwarder': 'right_key'}, ['', None], (False, 'Secrets are not configured')),
    ({'X-Custom-Forwarder': 'wrong_key'}, ['right_key', 'old_key'], (False, "Header didn't match any keys")),
])
def test_request_header_authorization(header, secrets, expected):
    builder = EnvironBuilder()
    builder.headers.extend(header)

# Path: notifications_utils/request_helper.py
# class NotifyRequest(Request):
#     """
#         A custom Request class, implementing extraction of zipkin headers used to trace request through cloudfoundry
#         as described here: https://docs.cloudfoundry.org/concepts/http-routing.html#zipkin-headers
#     """
# 
#     @property
#     def request_id(self):
#         return self.trace_id
# 
#     @property
#     def trace_id(self):
#         """
#             The "trace id" (in zipkin terms) assigned to this request, if present (None otherwise)
#         """
#         if not hasattr(self, "_trace_id"):
#             self._trace_id = self._get_header_value(current_app.config['NOTIFY_TRACE_ID_HEADER'])
#         return self._trace_id
# 
#     @property
#     def span_id(self):
#         """
#             The "span id" (in zipkin terms) set in this request's header, if present (None otherwise)
#         """
#         if not hasattr(self, "_span_id"):
#             # note how we don't generate an id of our own. not being supplied a span id implies that we are running in
#             # an environment with no span-id-aware request router, and thus would have no intermediary to prevent the
#             # propagation of our span id all the way through all our onwards requests much like trace id. and the point
#             # of span id is to assign identifiers to each individual request.
#             self._span_id = self._get_header_value(current_app.config['NOTIFY_SPAN_ID_HEADER'])
#         return self._span_id
# 
#     @property
#     def parent_span_id(self):
#         """
#             The "parent span id" (in zipkin terms) set in this request's header, if present (None otherwise)
#         """
#         if not hasattr(self, "_parent_span_id"):
#             self._parent_span_id = self._get_header_value(current_app.config['NOTIFY_PARENT_SPAN_ID_HEADER'])
#         return self._parent_span_id
# 
#     def _get_header_value(self, header_name):
#         """
#         Returns value of the given header
#         """
#         if header_name in self.headers and self.headers[header_name]:
#             return self.headers[header_name]
# 
#         return None
# 
# def _check_proxy_header_secret(request, secrets, header='X-Custom-Forwarder'):
#     if header not in request.headers:
#         return False, "Header missing"
# 
#     header_secret = request.headers.get(header)
#     if not header_secret:
#         return False, "Header exists but is empty"
# 
#     # if there isn't any non-empty secret configured we fail closed
#     if not any(secrets):
#         return False, "Secrets are not configured"
# 
#     for i, secret in enumerate(secrets):
#         if header_secret == secret:
#             return True, "Key used: {}".format(i + 1)  # add 1 to make it human-compatible
# 
#     return False, "Header didn't match any keys"


# Path: tests/test_request_header_authentication.py
from unittest import mock  # noqa
from werkzeug.test import EnvironBuilder
from notifications_utils.request_helper import (
    NotifyRequest,
    _check_proxy_header_secret,
)
import pytest





@pytest.mark.parametrize('header,secrets,expected', [
    ({'X-Custom-Forwarder': 'right_key'}, ['right_key', 'old_key'], (True, 'Key used: 1')),
    ({'X-Custom-Forwarder': 'right_key'}, ['right_key'], (True, 'Key used: 1')),
    ({'X-Custom-Forwarder': 'right_key'}, ['right_key', ''], (True, 'Key used: 1')),
    ({'My-New-Header': 'right_key'}, ['right_key', ''], (True, 'Key used: 1')),
    ({'X-Custom-Forwarder': 'right_key'}, ['', 'right_key'], (True, 'Key used: 2')),
    ({'X-Custom-Forwarder': 'right_key'}, ['', 'old_key', 'right_key'], (True, 'Key used: 3')),
    ({'X-Custom-Forwarder': ''}, ['right_key', 'old_key'], (False, 'Header exists but is empty')),
    ({'X-Custom-Forwarder': 'right_key'}, ['', None], (False, 'Secrets are not configured')),
    ({'X-Custom-Forwarder': 'wrong_key'}, ['right_key', 'old_key'], (False, "Header didn't match any keys")),
])
def test_request_header_authorization(header, secrets, expected):
    builder = EnvironBuilder()
    builder.headers.extend(header)

    request = NotifyRequest(builder.get_environ())