Skip to content

Commit 0593c37

Browse files
authored
Don't send empty credentials to SR in Authorization Header (confluentinc#863)
1 parent ffdab35 commit 0593c37

File tree

8 files changed

+60
-13
lines changed

8 files changed

+60
-13
lines changed

confluent_kafka/schema_registry/schema_registry_client.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,7 @@ def __init__(self, conf):
110110
raise ValueError("basic.auth.user.info must be in the form"
111111
" of {username}:{password}")
112112

113-
self.session.auth = userinfo
113+
self.session.auth = userinfo if userinfo != ('', '') else None
114114

115115
# Any leftover keys are unknown to _RestClient
116116
if len(conf_copy) > 0:

examples/adminapi.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -270,8 +270,9 @@ def example_list(a, args):
270270
else:
271271
errstr = ""
272272

273-
print(" partition {} leader: {}, replicas: {}, isrs: {}".format(
274-
p.id, p.leader, p.replicas, p.isrs, errstr))
273+
print("partition {} leader: {}, replicas: {},"
274+
" isrs: {} errstr: {}".format(p.id, p.leader, p.replicas,
275+
p.isrs, errstr))
275276

276277

277278
if __name__ == '__main__':

tests/integration/producer/test_transactions.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,8 +41,8 @@ def prefixed_delivery_cb(prefix):
4141
def delivery_err(err, msg):
4242
""" Reports failed message delivery to aid in troubleshooting test failures. """
4343
if err:
44-
print("[{}]: Message delivery failed (%s [%s]): %s".format(prefix,
45-
(msg.topic(), str(msg.partition()), err)))
44+
print("[{}]: Message delivery failed ({} [{}]): {}".format(
45+
prefix, msg.topic(), str(msg.partition()), err))
4646
return
4747

4848
return delivery_err

tests/integration/schema_registry/test_api_client.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -413,6 +413,6 @@ def test_api_config_update(kafka_cluster):
413413
"""
414414
sr = kafka_cluster.schema_registry()
415415

416-
for l in ["BACKWARD", "BACKWARD_TRANSITIVE", "FORWARD", "FORWARD_TRANSITIVE"]:
417-
sr.set_compatibility(level=l)
418-
assert sr.get_compatibility()['compatibilityLevel'] == l
416+
for level in ["BACKWARD", "BACKWARD_TRANSITIVE", "FORWARD", "FORWARD_TRANSITIVE"]:
417+
sr.set_compatibility(level=level)
418+
assert sr.get_compatibility()['compatibilityLevel'] == level

tests/schema_registry/conftest.py

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,12 @@
1717
#
1818
import os
1919
import re
20+
from base64 import b64decode
2021
from collections import defaultdict
2122

2223
import pytest
2324
import requests_mock
25+
from requests_mock import create_response
2426

2527
from confluent_kafka.schema_registry.schema_registry_client import \
2628
SchemaRegistryClient
@@ -68,6 +70,8 @@ class MockSchemaRegistryClient(SchemaRegistryClient):
6870
the only endpoint which supports this is /config which will return an
6971
`Invalid compatibility level` error.
7072
73+
To coerce Authentication errors configure credentials to
74+
not match MockSchemaRegistryClient.USERINFO.
7175
7276
Request paths to trigger exceptions:
7377
+--------+----------------------------------+-------+------------------------------+
@@ -130,6 +134,7 @@ class MockSchemaRegistryClient(SchemaRegistryClient):
130134
VERSIONS = [1, 2, 3, 4]
131135
SCHEMA = 'basic_schema.avsc'
132136
SUBJECTS = ['subject1', 'subject2']
137+
USERINFO = 'mock_user:mock_password'
133138

134139
# Counts requests handled per path by HTTP method
135140
# {HTTP method: { path : count}}
@@ -164,8 +169,29 @@ def __init__(self, conf):
164169
adapter.register_uri('POST', self.subject_versions,
165170
json=self.post_subject_version_callback)
166171

172+
adapter.add_matcher(self._auth_matcher)
167173
self._rest_client.session.mount('http://', adapter)
168174

175+
@classmethod
176+
def _auth_matcher(cls, request):
177+
headers = request._request.headers
178+
179+
authinfo = headers.get('Authorization', None)
180+
# Pass request to downstream matchers
181+
if authinfo is None:
182+
return None
183+
184+
# We only support the BASIC scheme today
185+
scheme, userinfo = authinfo.split(" ")
186+
if b64decode(userinfo) == cls.USERINFO:
187+
return None
188+
189+
unauthorized = {'error_code': 401,
190+
'message': "401 Unauthorized"}
191+
return create_response(request=request,
192+
status_code=401,
193+
json=unauthorized)
194+
169195
@staticmethod
170196
def _load_avsc(name):
171197
with open(os.path.join(work_dir, '..', 'integration', 'schema_registry',

tests/schema_registry/test_api_client.py

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,25 @@ def cmp_schema(schema1, schema2):
5555
schema1.schema_type == schema2.schema_type])
5656

5757

58+
def test_basic_auth_unauthorized(mock_schema_registry, load_avsc):
59+
conf = {'url': TEST_URL,
60+
'basic.auth.user.info': "user:secret"}
61+
sr = mock_schema_registry(conf)
62+
63+
with pytest.raises(SchemaRegistryError, match="401 Unauthorized"):
64+
sr.get_subjects()
65+
66+
67+
def test_basic_auth_authorized(mock_schema_registry, load_avsc):
68+
conf = {'url': TEST_URL,
69+
'basic.auth.user.info': mock_schema_registry.USERINFO}
70+
sr = mock_schema_registry(conf)
71+
72+
result = sr.get_subjects()
73+
74+
assert result == mock_schema_registry.SUBJECTS
75+
76+
5877
def test_register_schema(mock_schema_registry, load_avsc):
5978
conf = {'url': TEST_URL}
6079
sr = mock_schema_registry(conf)

tests/schema_registry/test_config.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -111,8 +111,8 @@ def test_config_auth_userinfo():
111111
'basic.auth.user.info': TEST_USERNAME + ':' + TEST_USER_PASSWORD}
112112

113113
test_client = SchemaRegistryClient(conf)
114-
assert test_client._rest_client.session.auth == [TEST_USERNAME,
115-
TEST_USER_PASSWORD]
114+
assert test_client._rest_client.session.auth == (TEST_USERNAME,
115+
TEST_USER_PASSWORD)
116116

117117

118118
def test_config_auth_userinfo_invalid():

tools/RELEASE.md

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -147,12 +147,13 @@ Create a new virtualenv:
147147

148148
Install the relevant package for your platform:
149149

150-
$ pip install dl-v0.11.4rc1/confluent_kafka-....whl
150+
$ pip install --no-cache-dir --find-links dl-v0.11.4rc1/ confluent-kafka
151151

152152
Verify that the package works, should print the expected Python client
153153
and librdkafka versions:
154154

155-
$ python -c 'import confluent_kafka as ck ; print "py:", ck.version(), "c:", ck.libversion()'
155+
$ python -c 'import confluent_kafka as ck ; print "py: {} c: {}" \
156+
.format(ck.version(), ck.libversion())'
156157
py: ('0.11.4', 721920) c: ('0.11.4-RC1', 722121)
157158

158159
## 10. Open a release PR
@@ -203,7 +204,7 @@ In the same virtualenv as created above:
203204

204205

205206
Verify that the package works and prints the expected version:
206-
$ python -c 'import confluent_kafka as ck ; print "py:", ck.version(), "c:", ck.libversion()'
207+
$ python -c 'import confluent_kafka as ck ; print("py:", ck.version(), "c:", ck.libversion())'
207208
py: ('0.11.4', 721920) c: ('0.11.4-RC1', 722121)
208209

209210

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy