Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[HOLD] Only allow x-trusted-proxy header to be valid for so long #574

Open
wants to merge 1 commit into
base: devel
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions ansible_base/jwt_consumer/common/util.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
import logging
import time
from base64 import b64encode

from cryptography.exceptions import InvalidSignature
from cryptography.hazmat.primitives import hashes, serialization
from cryptography.hazmat.primitives.asymmetric import padding

from ansible_base.jwt_consumer.common.cert import JWTCert, JWTCertException
from ansible_base.lib.utils.settings import get_setting

logger = logging.getLogger('ansible_base.jwt_consumer.common.util')

Expand Down Expand Up @@ -42,6 +44,15 @@ def validate_x_trusted_proxy_header(header_value: str, ignore_cache=False) -> bo
logger.warning("Failed to validate x-trusted-proxy-header, malformed, expected value to contain a -")
return False

# Validate that the header has been cut within the last 300ms (by default)
try:
if time.time_ns() - int(timestamp) > get_setting('trusted_header_timeout_in_ns', 300000000):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This requires that the clocks from the proxy server and the local server (using this auth class) are synced. I just want to have that in writing here.

logger.warning(f"Timestamp {timestamp} was too old to be valid alter trusted_header_timeout_in_ns if needed")
return False
except ValueError:
logger.warning(f"Unable to convert timestamp (base64) {b64encode(timestamp.encode('UTF-8'))} into an integer")
return False

try:
public_key.verify(
bytes.fromhex(signature),
Expand Down
22 changes: 22 additions & 0 deletions test_app/tests/jwt_consumer/common/test_util.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import time
from unittest import mock

from django.test.utils import override_settings
Expand Down Expand Up @@ -29,3 +30,24 @@ def test_validate_trusted_proxy_header_fail_load_public_key(self, mock_load_pem_
def test_validate_trusted_proxy_header_bad_public_key(self, random_public_key):
with override_settings(ANSIBLE_BASE_JWT_KEY=random_public_key):
assert not validate_x_trusted_proxy_header("0-12345123451234512345")

def test_header_timeout(self, expected_log, rsa_keypair):
header = generate_x_trusted_proxy_header(rsa_keypair.private)
with override_settings(ANSIBLE_BASE_JWT_KEY=rsa_keypair.public):
# Assert this header is valid if used right away
assert validate_x_trusted_proxy_header(header) is True

# By default the header is only valid for 300ms so a 1/2 second sleep will expire it
time.sleep(0.5)
with expected_log(
'ansible_base.jwt_consumer.common.util.logger', 'warning', 'was too old to be valid alter trusted_header_timeout_in_ns if needed'
):
assert validate_x_trusted_proxy_header(header) is False

def test_invalid_header_timestamp(self, expected_log, rsa_keypair):
header = generate_x_trusted_proxy_header(rsa_keypair.private)
_, signed_part = header.split('-')
header = f'asdf-{signed_part}'
with override_settings(ANSIBLE_BASE_JWT_KEY=rsa_keypair.public):
with expected_log('ansible_base.jwt_consumer.common.util.logger', 'warning', 'Unable to convert timestamp (base64)'):
assert validate_x_trusted_proxy_header(header) is False
Loading