Skip to content
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
68 changes: 68 additions & 0 deletions examples/http_adapter.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
#!/usr/bin/env python3
import argparse
from pathlib import Path
from typing import Optional
import ssl
from requests.adapters import HTTPAdapter
from urllib3.poolmanager import PoolManager

from redfish import redfish_client


def make_dhe_compatible_context(
cafile: Optional[Path] = None,
*,
seclevel: int = 1,
verify: bool = True,
tls12_only: bool = True,
) -> ssl.SSLContext:
"""
Build an SSLContext that accepts legacy DHE handshakes (small DH groups).
- seclevel=1 usually permits 1024-bit DH. Use 0 only as a last resort.
- If verify=True and the server is self-signed, pass its PEM as `cafile`.
- DHE is TLS<=1.2; set tls12_only=True to pin TLS 1.2.
"""
ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
ctx.set_ciphers(f"DEFAULT:@SECLEVEL={seclevel}:DHE")
ctx.options |= ssl.OP_NO_COMPRESSION
if tls12_only:
ctx.minimum_version = ssl.TLSVersion.TLSv1_2
ctx.maximum_version = ssl.TLSVersion.TLSv1_2

if verify:
if cafile:
ctx.load_verify_locations(str(cafile))
else:
ctx.load_default_certs()
else:
ctx.check_hostname = False
ctx.verify_mode = ssl.CERT_NONE
return ctx

class SSLContextAdapter(HTTPAdapter):
"""requests adapter that injects a custom ssl_context into urllib3."""
def __init__(self, ssl_context: ssl.SSLContext, **kwargs):
self._ssl_context = ssl_context
super().__init__(**kwargs)

def init_poolmanager(self, connections, maxsize, block=False, **pool_kwargs):
pool_kwargs["ssl_context"] = self._ssl_context
self.poolmanager = PoolManager(
num_pools=connections, maxsize=maxsize, block=block, **pool_kwargs
)

def proxy_manager_for(self, proxy, **proxy_kwargs):
proxy_kwargs["ssl_context"] = self._ssl_context
return super().proxy_manager_for(proxy, **proxy_kwargs)


# Test dhe adapter
ctx = make_dhe_compatible_context(seclevel=0, verify=False)
adapter = SSLContextAdapter(ctx)
parser = argparse.ArgumentParser( )
parser.add_argument('url',help="Server with DHE encryption")
args = parser.parse_args()

client = redfish_client(args.url,https_adapter=adapter)


29 changes: 19 additions & 10 deletions src/redfish/rest/v1.py
Original file line number Diff line number Diff line change
Expand Up @@ -468,7 +468,8 @@ class RestClientBase(object):
def __init__(self, base_url, username=None, password=None,
default_prefix='/redfish/v1/', sessionkey=None,
capath=None, cafile=None, timeout=None,
max_retry=None, proxies=None, check_connectivity=True):
max_retry=None, proxies=None, check_connectivity=True,
https_adapter = None):
"""Initialization of the base class RestClientBase

:param base_url: The URL of the remote system
Expand All @@ -494,7 +495,7 @@ def __init__(self, base_url, username=None, password=None,
:param check_connectivity: A boolean to determine whether the client immediately checks for
connectivity to the base_url or not.
:type check_connectivity: bool

:type https_adapter: requests.adpaters.HTTPAdapter
"""

self.__base_url = base_url.rstrip('/')
Expand All @@ -507,6 +508,8 @@ def __init__(self, base_url, username=None, password=None,
self._session = requests_unixsocket.Session()
else:
self._session = requests.Session()
if https_adapter:
self._session.mount('https://',https_adapter)
self._timeout = timeout
self._max_retry = max_retry if max_retry is not None else 10
self._proxies = proxies
Expand Down Expand Up @@ -1079,7 +1082,8 @@ def __init__(self, base_url, username=None, password=None,
default_prefix='/redfish/v1/',
sessionkey=None, capath=None,
cafile=None, timeout=None,
max_retry=None, proxies=None, check_connectivity=True):
max_retry=None, proxies=None, check_connectivity=True,
https_adapter=None):
"""Initialize HttpClient

:param base_url: The url of the remote system
Expand All @@ -1105,14 +1109,15 @@ def __init__(self, base_url, username=None, password=None,
:param check_connectivity: A boolean to determine whether the client immediately checks for
connectivity to the base_url or not.
:type check_connectivity: bool

:param https_adapter session adapter for HTTPS
:type https_adapter: requests.adpaters.HTTPAdapter
"""
super(HttpClient, self).__init__(base_url, username=username,
password=password, default_prefix=default_prefix,
sessionkey=sessionkey, capath=capath,
cafile=cafile, timeout=timeout,
max_retry=max_retry, proxies=proxies,
check_connectivity=check_connectivity)
check_connectivity=check_connectivity,https_adapter=https_adapter)

try:
self.login_url = self.root.Links.Sessions['@odata.id']
Expand Down Expand Up @@ -1169,7 +1174,8 @@ def redfish_client(base_url=None, username=None, password=None,
default_prefix='/redfish/v1/',
sessionkey=None, capath=None,
cafile=None, timeout=None,
max_retry=None, proxies=None, check_connectivity=True):
max_retry=None, proxies=None, check_connectivity=True,
https_adapter=None):
"""Create and return appropriate REDFISH client instance."""
""" Instantiates appropriate Redfish object based on existing"""
""" configuration. Use this to retrieve a pre-configured Redfish object
Expand All @@ -1196,14 +1202,17 @@ def redfish_client(base_url=None, username=None, password=None,
:type proxies: dict
:param check_connectivity: A boolean to determine whether the client immediately checks for
connectivity to the base_url or not.
:type check_connectivity: bool
:type check_connectivity: bo#ol
:param https_adapter session adapter for HTTPS
:type https_adapter: requests.adpaters.HTTPAdapter
:returns: a client object.

"""
if "://" not in base_url:
warnings.warn("Scheme not specified for '{}'; adding 'https://'".format(base_url))
base_url = "https://" + base_url
warnings.warn("Scheme not specified for '{}'; adding 'https://'".format(base_url))
base_url = "https://" + base_url
return HttpClient(base_url=base_url, username=username, password=password,
default_prefix=default_prefix, sessionkey=sessionkey,
capath=capath, cafile=cafile, timeout=timeout,
max_retry=max_retry, proxies=proxies, check_connectivity=check_connectivity)
max_retry=max_retry, proxies=proxies, check_connectivity=check_connectivity,
https_adapter=https_adapter)