Skip to content

Commit 87686d0

Browse files
Added password support for SSL private key of the cached schema registry client (confluentinc#1516)
* Steps to Test: 1) Run certify.sh 2) Manually run .env.sh code 3) docker-compose up [tests/docker] 4) Wait for the docker instance to be listening for requests(roughly 30 seconds) 5) run the command -> python3 integration_test.py --avro-https testconf.json In mac Systems the certify.sh takes the hostname and it then collides when https connection is to be made since the hostname should be mentioned in the keychain - so either change hostname command to localhost literal and then run on Mac, otherwise in Linux system it should be fine.
1 parent 17029ad commit 87686d0

File tree

7 files changed

+63
-6
lines changed

7 files changed

+63
-6
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
SASL PLAIN/SCRAM credentials that will be used for subsequent (new) connections to a broker (#1511).
77
- Wheels for Linux / arm64 (#1496).
88
- Added support for Default num_partitions in CreateTopics Admin API.
9+
- Added support for password protected private key in CachedSchemaRegistryClient.
910

1011
## v2.0.2
1112

src/confluent_kafka/avro/cached_schema_registry_client.py

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@
2121
#
2222
import logging
2323
import warnings
24+
import urllib3
25+
import json
2426
from collections import defaultdict
2527

2628
from requests import Session, utils
@@ -54,6 +56,7 @@ class CachedSchemaRegistryClient(object):
5456
Use CachedSchemaRegistryClient(dict: config) instead.
5557
Existing params ca_location, cert_location and key_location will be replaced with their librdkafka equivalents:
5658
`ssl.ca.location`, `ssl.certificate.location` and `ssl.key.location` respectively.
59+
The support for password protected private key is via the Config only using 'ssl.key.password' field.
5760
5861
Errors communicating to the server will result in a ClientError being raised.
5962
@@ -109,6 +112,9 @@ def __init__(self, url, max_schemas_per_subject=1000, ca_location=None, cert_loc
109112
self.url = utils.urldefragauth(self.url)
110113

111114
self._session = s
115+
key_password = conf.pop('ssl.key.password', None)
116+
self._is_key_password_provided = not key_password
117+
self._https_session = self._make_https_session(s.cert[0], s.cert[1], ca_path, s.auth, key_password)
112118

113119
self.auto_register_schemas = conf.pop("auto.register.schemas", True)
114120

@@ -128,6 +134,29 @@ def close(self):
128134
# Constructor exceptions may occur prior to _session being set.
129135
if hasattr(self, '_session'):
130136
self._session.close()
137+
if hasattr(self, '_https_session'):
138+
self._https_session.clear()
139+
140+
@staticmethod
141+
def _make_https_session(cert_location, key_location, ca_certs_path, auth, key_password):
142+
https_session = urllib3.PoolManager(cert_reqs='CERT_REQUIRED', ca_certs=ca_certs_path,
143+
cert_file=cert_location, key_file=key_location, key_password=key_password)
144+
https_session.auth = auth
145+
return https_session
146+
147+
def _send_https_session_request(self, url, method, headers, body):
148+
request_headers = {'Accept': ACCEPT_HDR}
149+
auth = self._https_session.auth
150+
if body:
151+
body = json.dumps(body).encode('UTF-8')
152+
request_headers["Content-Length"] = str(len(body))
153+
request_headers["Content-Type"] = "application/vnd.schemaregistry.v1+json"
154+
if auth[0] != '' and auth[1] != '':
155+
request_headers.update(urllib3.make_headers(basic_auth=auth[0] + ":" +
156+
auth[1]))
157+
request_headers.update(headers)
158+
response = self._https_session.request(method, url, headers=request_headers, body=body)
159+
return response
131160

132161
@staticmethod
133162
def _configure_basic_auth(url, conf):
@@ -158,6 +187,13 @@ def _send_request(self, url, method='GET', body=None, headers={}):
158187
if method not in VALID_METHODS:
159188
raise ClientError("Method {} is invalid; valid methods include {}".format(method, VALID_METHODS))
160189

190+
if url.startswith('https') and self._is_key_password_provided:
191+
response = self._send_https_session_request(url, method, headers, body)
192+
try:
193+
return json.loads(response.data), response.status
194+
except ValueError:
195+
return response.content, response.status
196+
161197
_headers = {'Accept': ACCEPT_HDR}
162198
if body:
163199
_headers["Content-Length"] = str(len(body))

tests/docker/.env.sh

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,3 +13,5 @@ export MY_SCHEMA_REGISTRY_SSL_URL_ENV=https://$(hostname -f):8082
1313
export MY_SCHEMA_REGISTRY_SSL_CA_LOCATION_ENV=$TLS/ca-cert
1414
export MY_SCHEMA_REGISTRY_SSL_CERTIFICATE_LOCATION_ENV=$TLS/client.pem
1515
export MY_SCHEMA_REGISTRY_SSL_KEY_LOCATION_ENV=$TLS/client.key
16+
export MY_SCHEMA_REGISTRY_SSL_KEY_WITH_PASSWORD_LOCATION_ENV=$TLS/client_with_password.key
17+
export MY_SCHEMA_REGISTRY_SSL_KEY_PASSWORD="abcdefgh"

tests/docker/bin/certify.sh

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,5 +24,6 @@ echo "Creating client cert..."
2424
${PY_DOCKER_BIN}/gen-ssl-certs.sh client ${TLS}/ca-cert ${TLS}/ ${HOST} ${HOST}
2525

2626
echo "Creating key ..."
27+
cp ${TLS}/client.key ${TLS}/client_with_password.key
2728
openssl rsa -in ${TLS}/client.key -out ${TLS}/client.key -passin pass:${PASS}
2829

tests/docker/docker-compose.yaml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ services:
2121
KAFKA_AUTHORIZER_CLASS_NAME: kafka.security.authorizer.AclAuthorizer
2222
KAFKA_SUPER_USERS: "User:ANONYMOUS"
2323
schema-registry:
24-
image: confluentinc/cp-schema-registry:7.1.0
24+
image: confluentinc/cp-schema-registry
2525
depends_on:
2626
- zookeeper
2727
- kafka
@@ -42,7 +42,7 @@ services:
4242
SCHEMA_REGISTRY_SSL_TRUSTSTORE_PASSWORD: abcdefgh
4343
SCHEMA_REGISTRY_KAFKASTORE_CONNECTION_URL: zookeeper:2181
4444
schema-registry-basic-auth:
45-
image: confluentinc/cp-schema-registry:7.1.0
45+
image: confluentinc/cp-schema-registry
4646
depends_on:
4747
- zookeeper
4848
- kafka

tests/integration/integration_test.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1254,6 +1254,16 @@ def print_usage(exitcode, reason=None):
12541254
if 'avro-https' in modes:
12551255
print('=' * 30, 'Verifying AVRO with HTTPS', '=' * 30)
12561256
verify_avro_https(testconf.get('avro-https', None))
1257+
key_with_password_conf = testconf.get("avro-https-key-with-password", None)
1258+
print('=' * 30, 'Verifying AVRO with HTTPS Flow with Password',
1259+
'Protected Private Key of Cached-Schema-Registry-Client', '=' * 30)
1260+
verify_avro_https(key_with_password_conf)
1261+
print('Verifying Error with Wrong Password of Password Protected Private Key of Cached-Schema-Registry-Client')
1262+
try:
1263+
key_with_password_conf['schema.registry.ssl.key.password'] += '->wrongpassword'
1264+
verify_avro_https(key_with_password_conf)
1265+
except Exception:
1266+
print("Wrong Password Gives Error -> Successful")
12571267

12581268
if 'avro-basic-auth' in modes:
12591269
print("=" * 30, 'Verifying AVRO with Basic Auth', '=' * 30)

tests/integration/testconf.json

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,15 +3,22 @@
33
"bootstrap.servers": "$MY_BOOTSTRAP_SERVER_ENV",
44
"schema.registry.url": "$MY_SCHEMA_REGISTRY_URL_ENV",
55
"avro-https": {
6-
"schema.registry.url": "$MY_SCHEMA_REGISTRY_SSL_URL_ENV",
7-
"schema.registry.ssl.ca.location": "$MY_SCHEMA_REGISTRY_SSL_CA_LOCATION_ENV",
8-
"schema.registry.ssl.certificate.location": "$MY_SCHEMA_REGISTRY_SSL_CERTIFICATE_LOCATION_ENV",
9-
"schema.registry.ssl.key.location": "$MY_SCHEMA_REGISTRY_SSL_KEY_LOCATION_ENV"
6+
"schema.registry.url": "$MY_SCHEMA_REGISTRY_SSL_URL_ENV",
7+
"schema.registry.ssl.ca.location": "$MY_SCHEMA_REGISTRY_SSL_CA_LOCATION_ENV",
8+
"schema.registry.ssl.certificate.location": "$MY_SCHEMA_REGISTRY_SSL_CERTIFICATE_LOCATION_ENV",
9+
"schema.registry.ssl.key.location": "$MY_SCHEMA_REGISTRY_SSL_KEY_LOCATION_ENV"
1010
},
1111
"avro-basic-auth": {
1212
"schema.registry.url": "http://localhost:8083",
1313
"schema.registry.basic.auth.user.info": "ckp_tester:test_secret",
1414
"sasl.username": "ckp_tester",
1515
"sasl.password": "test_secret"
16+
},
17+
"avro-https-key-with-password": {
18+
"schema.registry.url": "$MY_SCHEMA_REGISTRY_SSL_URL_ENV",
19+
"schema.registry.ssl.ca.location": "$MY_SCHEMA_REGISTRY_SSL_CA_LOCATION_ENV",
20+
"schema.registry.ssl.certificate.location": "$MY_SCHEMA_REGISTRY_SSL_CERTIFICATE_LOCATION_ENV",
21+
"schema.registry.ssl.key.location": "$MY_SCHEMA_REGISTRY_SSL_KEY_WITH_PASSWORD_LOCATION_ENV",
22+
"schema.registry.ssl.key.password": "$MY_SCHEMA_REGISTRY_SSL_KEY_PASSWORD"
1623
}
1724
}

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