Skip to content

Commit 4d3a76b

Browse files
Dos MoonenDarsstar
authored andcommitted
Refactor SslConfigurationContext into platform specific classes
1 parent 884cc8b commit 4d3a76b

File tree

10 files changed

+195
-54
lines changed

10 files changed

+195
-54
lines changed

examples/getting_started/getting_started.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
# type: ignore
22

33

4-
from rabbitmq_amqp_python_client import ( # SSlConfigurationContext,; SslConfigurationContext,; ClientCert,
4+
from rabbitmq_amqp_python_client import ( # PosixSSlConfigurationContext,; PosixClientCert,
55
AddressHelper,
66
AMQPMessagingHandler,
77
Connection,
@@ -68,7 +68,7 @@ def create_connection(environment: Environment) -> Connection:
6868
# client_key = ".ci/certs/client_key.pem"
6969
# connection = Connection(
7070
# "amqps://guest:guest@localhost:5671/",
71-
# ssl_context=SslConfigurationContext(
71+
# ssl_context=PosixSslConfigurationContext(
7272
# ca_cert=ca_cert_file,
7373
# client_cert=ClientCert(client_cert=client_cert, client_key=client_key),
7474
# ),

examples/streams/example_with_streams.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# type: ignore
22

3-
from rabbitmq_amqp_python_client import ( # SSlConfigurationContext,; SslConfigurationContext,; ClientCert,
3+
from rabbitmq_amqp_python_client import ( # PosixSSlConfigurationContext,; PosixClientCert,
44
AddressHelper,
55
AMQPMessagingHandler,
66
Connection,
@@ -72,9 +72,9 @@ def create_connection(environment: Environment) -> Connection:
7272
# client_key = ".ci/certs/client_key.pem"
7373
# connection = Connection(
7474
# "amqps://guest:guest@localhost:5671/",
75-
# ssl_context=SslConfigurationContext(
75+
# ssl_context=PosixSslConfigurationContext(
7676
# ca_cert=ca_cert_file,
77-
# client_cert=ClientCert(client_cert=client_cert, client_key=client_key),
77+
# client_cert=PosixClientCert(client_cert=client_cert, client_key=client_key),
7878
# ),
7979
# )
8080
connection.dial()

examples/tls/tls_example.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,18 @@
11
# type: ignore
22

33

4-
from rabbitmq_amqp_python_client import ( # SSlConfigurationContext,; SslConfigurationContext,; ClientCert,
4+
from rabbitmq_amqp_python_client import (
55
AddressHelper,
66
AMQPMessagingHandler,
7-
ClientCert,
87
Connection,
98
Environment,
109
Event,
1110
ExchangeSpecification,
1211
ExchangeToQueueBindingSpecification,
1312
Message,
13+
PosixClientCert,
14+
PosixSslConfigurationContext,
1415
QuorumQueueSpecification,
15-
SslConfigurationContext,
1616
)
1717

1818
messages_to_publish = 100
@@ -80,9 +80,9 @@ def main() -> None:
8080

8181
environment = Environment(
8282
"amqps://guest:guest@localhost:5671/",
83-
ssl_context=SslConfigurationContext(
83+
ssl_context=PosixSslConfigurationContext(
8484
ca_cert=ca_cert_file,
85-
client_cert=ClientCert(client_cert=client_cert, client_key=client_key),
85+
client_cert=PosixClientCert(client_cert=client_cert, client_key=client_key),
8686
),
8787
)
8888

rabbitmq_amqp_python_client/__init__.py

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -32,8 +32,13 @@
3232
StreamSpecification,
3333
)
3434
from .ssl_configuration import (
35-
ClientCert,
36-
SslConfigurationContext,
35+
CurrentUserStore,
36+
LocalMachineStore,
37+
PKCS12Store,
38+
PosixClientCert,
39+
PosixSslConfigurationContext,
40+
WinClientCert,
41+
WinSslConfigurationContext,
3742
)
3843

3944
try:
@@ -69,8 +74,13 @@
6974
"AMQPMessagingHandler",
7075
"ArgumentOutOfRangeException",
7176
"ValidationCodeException",
72-
"SslConfigurationContext",
73-
"ClientCert",
77+
"PosixSslConfigurationContext",
78+
"WinSslConfigurationContext",
79+
"PosixClientCert",
80+
"WinClientCert",
81+
"LocalMachineStore",
82+
"CurrentUserStore",
83+
"PKCS12Store",
7484
"ConnectionClosed",
7585
"StreamOptions",
7686
"OffsetSpecification",

rabbitmq_amqp_python_client/connection.py

Lines changed: 74 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,13 @@
11
import logging
2-
from typing import Annotated, Callable, Optional, TypeVar
2+
from typing import (
3+
Annotated,
4+
Callable,
5+
Optional,
6+
TypeVar,
7+
Union,
8+
)
9+
10+
import typing_extensions
311

412
from .address_helper import validate_address
513
from .consumer import Consumer
@@ -10,7 +18,15 @@
1018
from .qpid.proton._handlers import MessagingHandler
1119
from .qpid.proton._transport import SSLDomain
1220
from .qpid.proton.utils import BlockingConnection
13-
from .ssl_configuration import SslConfigurationContext
21+
from .ssl_configuration import (
22+
CurrentUserStore,
23+
FriendlyName,
24+
LocalMachineStore,
25+
PKCS12Store,
26+
PosixSslConfigurationContext,
27+
Unambiguous,
28+
WinSslConfigurationContext,
29+
)
1430

1531
logger = logging.getLogger(__name__)
1632

@@ -34,7 +50,9 @@ def __init__(
3450
uri: Optional[str] = None,
3551
# multi-node mode
3652
uris: Optional[list[str]] = None,
37-
ssl_context: Optional[SslConfigurationContext] = None,
53+
ssl_context: Union[
54+
PosixSslConfigurationContext, WinSslConfigurationContext, None
55+
] = None,
3856
on_disconnection_handler: Optional[CB] = None, # type: ignore
3957
):
4058
"""
@@ -60,7 +78,9 @@ def __init__(
6078
self._conn: BlockingConnection
6179
self._management: Management
6280
self._on_disconnection_handler = on_disconnection_handler
63-
self._conf_ssl_context: Optional[SslConfigurationContext] = ssl_context
81+
self._conf_ssl_context: Union[
82+
PosixSslConfigurationContext, WinSslConfigurationContext, None
83+
] = ssl_context
6484
self._ssl_domain = None
6585
self._connections = [] # type: ignore
6686
self._index: int = -1
@@ -80,17 +100,47 @@ def dial(self) -> None:
80100
logger.debug("Enabling SSL")
81101

82102
self._ssl_domain = SSLDomain(SSLDomain.MODE_CLIENT)
83-
if self._ssl_domain is not None:
84-
self._ssl_domain.set_trusted_ca_db(self._conf_ssl_context.ca_cert)
103+
assert self._ssl_domain
104+
105+
if isinstance(self._conf_ssl_context, PosixSslConfigurationContext):
106+
ca_cert = self._conf_ssl_context.ca_cert
107+
elif isinstance(self._conf_ssl_context, WinSslConfigurationContext):
108+
ca_cert = self._win_store_to_cert(self._conf_ssl_context.ca_store)
109+
else:
110+
typing_extensions.assert_never(self._conf_ssl_context)
111+
self._ssl_domain.set_trusted_ca_db(ca_cert)
112+
85113
# for mutual authentication
86114
if self._conf_ssl_context.client_cert is not None:
87115
logger.debug("Enabling mutual authentication as well")
88-
if self._ssl_domain is not None:
89-
self._ssl_domain.set_credentials(
90-
self._conf_ssl_context.client_cert.client_cert,
91-
self._conf_ssl_context.client_cert.client_key,
92-
self._conf_ssl_context.client_cert.password,
116+
117+
if isinstance(self._conf_ssl_context, PosixSslConfigurationContext):
118+
client_cert = self._conf_ssl_context.client_cert.client_cert
119+
client_key = self._conf_ssl_context.client_cert.client_key
120+
password = self._conf_ssl_context.client_cert.password
121+
elif isinstance(self._conf_ssl_context, WinSslConfigurationContext):
122+
client_cert = self._win_store_to_cert(
123+
self._conf_ssl_context.client_cert.store
93124
)
125+
disambiguation_method = (
126+
self._conf_ssl_context.client_cert.disambiguation_method
127+
)
128+
if isinstance(disambiguation_method, Unambiguous):
129+
client_key = None
130+
elif isinstance(disambiguation_method, FriendlyName):
131+
client_key = disambiguation_method.name
132+
else:
133+
typing_extensions.assert_never(disambiguation_method)
134+
135+
password = self._conf_ssl_context.client_cert.password
136+
else:
137+
typing_extensions.assert_never(self._conf_ssl_context)
138+
139+
self._ssl_domain.set_credentials(
140+
client_cert,
141+
client_key,
142+
password,
143+
)
94144
self._conn = BlockingConnection(
95145
url=self._addr,
96146
urls=self._addrs,
@@ -100,6 +150,19 @@ def dial(self) -> None:
100150
self._open()
101151
logger.debug("Connection to the server established")
102152

153+
def _win_store_to_cert(
154+
self, store: Union[LocalMachineStore, CurrentUserStore, PKCS12Store]
155+
) -> str:
156+
if isinstance(store, LocalMachineStore):
157+
ca_cert = f"lmss:{store.name}"
158+
elif isinstance(store, CurrentUserStore):
159+
ca_cert = f"ss:{store.name}"
160+
elif isinstance(store, PKCS12Store):
161+
ca_cert = store.path
162+
else:
163+
typing_extensions.assert_never(store)
164+
return ca_cert
165+
103166
def _open(self) -> None:
104167
self._management = Management(self._conn)
105168
self._management.open()

rabbitmq_amqp_python_client/environment.py

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,18 @@
11
# For the moment this is just a Connection pooler to keep compatibility with other clients
22
import logging
3-
from typing import Annotated, Callable, Optional, TypeVar
3+
from typing import (
4+
Annotated,
5+
Callable,
6+
Optional,
7+
TypeVar,
8+
Union,
9+
)
410

511
from .connection import Connection
6-
from .ssl_configuration import SslConfigurationContext
12+
from .ssl_configuration import (
13+
PosixSslConfigurationContext,
14+
WinSslConfigurationContext,
15+
)
716

817
logger = logging.getLogger(__name__)
918

@@ -28,7 +37,9 @@ def __init__(
2837
uri: Optional[str] = None,
2938
# multi-node mode
3039
uris: Optional[list[str]] = None,
31-
ssl_context: Optional[SslConfigurationContext] = None,
40+
ssl_context: Union[
41+
PosixSslConfigurationContext, WinSslConfigurationContext, None
42+
] = None,
3243
on_disconnection_handler: Optional[CB] = None, # type: ignore
3344
):
3445
"""

rabbitmq_amqp_python_client/qpid/proton/_transport.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -826,7 +826,7 @@ def __init__(self, mode: int) -> None:
826826
def _check(self, err: int) -> int:
827827
if err < 0:
828828
exc = EXCEPTIONS.get(err, SSLException)
829-
raise exc("SSL failure.")
829+
raise exc("SSL failure.", err)
830830
else:
831831
return err
832832

Lines changed: 46 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,57 @@
11
from dataclasses import dataclass
2-
from typing import Optional
2+
from typing import Optional, Union
33

44

55
@dataclass
6-
class ClientCert:
6+
class PosixClientCert:
77
client_cert: str
88
client_key: str
99
password: Optional[str] = None
1010

1111

1212
@dataclass
13-
class SslConfigurationContext:
13+
class Unambiguous:
14+
"""Use the only certificate in the store."""
15+
16+
...
17+
18+
19+
@dataclass
20+
class FriendlyName:
21+
"""Use the first certificate with a matching friendly name."""
22+
23+
name: str
24+
25+
26+
@dataclass
27+
class LocalMachineStore:
28+
name: str
29+
30+
31+
@dataclass
32+
class CurrentUserStore:
33+
name: str
34+
35+
36+
@dataclass
37+
class PKCS12Store:
38+
path: str
39+
40+
41+
@dataclass
42+
class WinClientCert:
43+
store: Union[LocalMachineStore, CurrentUserStore, PKCS12Store]
44+
disambiguation_method: Union[Unambiguous, FriendlyName]
45+
password: Optional[str] = None
46+
47+
48+
@dataclass
49+
class PosixSslConfigurationContext:
1450
ca_cert: str
15-
client_cert: Optional[ClientCert] = None
51+
client_cert: Union[PosixClientCert, WinClientCert, None] = None
52+
53+
54+
@dataclass
55+
class WinSslConfigurationContext:
56+
ca_store: Union[LocalMachineStore, CurrentUserStore, PKCS12Store]
57+
client_cert: Union[PosixClientCert, WinClientCert, None] = None

0 commit comments

Comments
 (0)