Skip to content
Merged
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
10 changes: 9 additions & 1 deletion duo_client/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
from .https_wrapper import CertValidatingHTTPSConnection

DEFAULT_CA_CERTS = os.path.join(os.path.dirname(__file__), 'ca_certs.pem')
CA_BUNDLE_VERSION = '1.0'


def canon_params(params):
Expand Down Expand Up @@ -243,7 +244,14 @@ def __init__(self, ikey, skey, host,
if ca_certs is None:
ca_certs = DEFAULT_CA_CERTS
self.ca_certs = ca_certs
self.user_agent = user_agent
ca_pinning_status = 'disabled' if disable_ca_pinning else 'enabled'
if user_agent:
self.user_agent = (
f"{user_agent} ca_bundle/{CA_BUNDLE_VERSION}"
f" (ca_pinning={ca_pinning_status})"
)
else:
self.user_agent = user_agent
self.set_proxy(host=None, proxy_type=None)
self.paging_limit = paging_limit
self.digestmod = digestmod
Expand Down
44 changes: 44 additions & 0 deletions tests/test_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -806,6 +806,50 @@ def test_disable_ca_pinning_with_disable_ca_certs_raises(self):
self.assertIn("Cannot both disable CA pinning", str(ctx.exception))


class TestUserAgent(unittest.TestCase):
"""Tests for user agent string including CA bundle version and pinning status."""

def test_default_user_agent_includes_ca_bundle_version(self):
client = duo_client.client.Client('ikey', 'skey', 'host.example.com')
self.assertIn(
f"ca_bundle/{duo_client.client.CA_BUNDLE_VERSION}",
client.user_agent,
)

def test_default_user_agent_includes_ca_pinning_enabled(self):
client = duo_client.client.Client('ikey', 'skey', 'host.example.com')
self.assertIn("(ca_pinning=enabled)", client.user_agent)

def test_user_agent_includes_ca_pinning_disabled(self):
client = duo_client.client.Client('ikey', 'skey', 'host.example.com',
disable_ca_pinning=True)
self.assertIn("(ca_pinning=disabled)", client.user_agent)

def test_default_user_agent_format(self):
client = duo_client.client.Client('ikey', 'skey', 'host.example.com')
expected = (
f"Duo API Python/{duo_client.client.__version__}"
f" ca_bundle/{duo_client.client.CA_BUNDLE_VERSION}"
f" (ca_pinning=enabled)"
)
self.assertEqual(client.user_agent, expected)

def test_custom_user_agent_includes_ca_fields(self):
client = duo_client.client.Client('ikey', 'skey', 'host.example.com',
user_agent='MyApp/1.0')
expected = (
f"MyApp/1.0"
f" ca_bundle/{duo_client.client.CA_BUNDLE_VERSION}"
f" (ca_pinning=enabled)"
)
self.assertEqual(client.user_agent, expected)

def test_empty_user_agent_not_modified(self):
client = duo_client.client.Client('ikey', 'skey', 'host.example.com',
user_agent='')
self.assertEqual(client.user_agent, '')


class TestDisableCaPinningConnect(unittest.TestCase):
"""Tests that _connect() uses the correct connection type."""

Expand Down
Loading