summaryrefslogtreecommitdiff
path: root/ironic
diff options
context:
space:
mode:
Diffstat (limited to 'ironic')
-rw-r--r--ironic/drivers/modules/redfish/utils.py61
-rw-r--r--ironic/tests/unit/drivers/modules/redfish/test_utils.py16
2 files changed, 55 insertions, 22 deletions
diff --git a/ironic/drivers/modules/redfish/utils.py b/ironic/drivers/modules/redfish/utils.py
index 40cf33bce..e85e2ec6a 100644
--- a/ironic/drivers/modules/redfish/utils.py
+++ b/ironic/drivers/modules/redfish/utils.py
@@ -15,6 +15,7 @@
# under the License.
import collections
+import hashlib
import os
from urllib import parse as urlparse
@@ -198,43 +199,59 @@ class SessionCache(object):
_sessions = collections.OrderedDict()
def __init__(self, driver_info):
+ # Hash the password in the data structure, so we can
+ # include it in the session key.
+ # NOTE(TheJulia): Multiplying the address by 4, to ensure
+ # we meet a minimum of 16 bytes for salt.
+ pw_hash = hashlib.pbkdf2_hmac(
+ 'sha512',
+ driver_info.get('password').encode('utf-8'),
+ str(driver_info.get('address') * 4).encode('utf-8'), 40)
self._driver_info = driver_info
+ # Assemble the session key and append the hashed password to it,
+ # which forces new sessions to be established when the saved password
+ # is changed, just like the username, or address.
self._session_key = tuple(
self._driver_info.get(key)
for key in ('address', 'username', 'verify_ca')
- )
+ ) + (pw_hash.hex(),)
def __enter__(self):
try:
return self.__class__._sessions[self._session_key]
-
except KeyError:
- auth_type = self._driver_info['auth_type']
+ LOG.debug('A cached redfish session for Redfish endpoint '
+ '%(endpoint)s was not detected, initiating a session.',
+ {'endpoint': self._driver_info['address']})
- auth_class = self.AUTH_CLASSES[auth_type]
+ auth_type = self._driver_info['auth_type']
- authenticator = auth_class(
- username=self._driver_info['username'],
- password=self._driver_info['password']
- )
+ auth_class = self.AUTH_CLASSES[auth_type]
- sushy_params = {'verify': self._driver_info['verify_ca'],
- 'auth': authenticator}
- if 'root_prefix' in self._driver_info:
- sushy_params['root_prefix'] = self._driver_info['root_prefix']
- conn = sushy.Sushy(
- self._driver_info['address'],
- **sushy_params
- )
+ authenticator = auth_class(
+ username=self._driver_info['username'],
+ password=self._driver_info['password']
+ )
+
+ sushy_params = {'verify': self._driver_info['verify_ca'],
+ 'auth': authenticator}
+ if 'root_prefix' in self._driver_info:
+ sushy_params['root_prefix'] = self._driver_info['root_prefix']
+ conn = sushy.Sushy(
+ self._driver_info['address'],
+ **sushy_params
+ )
- if CONF.redfish.connection_cache_size:
- self.__class__._sessions[self._session_key] = conn
+ if CONF.redfish.connection_cache_size:
+ self.__class__._sessions[self._session_key] = conn
+ # Save a secure hash of the password into memory, so if we
+ # observe it change, we can detect the session is no longer valid.
- if (len(self.__class__._sessions)
- > CONF.redfish.connection_cache_size):
- self._expire_oldest_session()
+ if (len(self.__class__._sessions)
+ > CONF.redfish.connection_cache_size):
+ self._expire_oldest_session()
- return conn
+ return conn
def __exit__(self, exc_type, exc_val, exc_tb):
# NOTE(etingof): perhaps this session token is no good
diff --git a/ironic/tests/unit/drivers/modules/redfish/test_utils.py b/ironic/tests/unit/drivers/modules/redfish/test_utils.py
index ca8aba9da..01b7089c7 100644
--- a/ironic/tests/unit/drivers/modules/redfish/test_utils.py
+++ b/ironic/tests/unit/drivers/modules/redfish/test_utils.py
@@ -252,6 +252,7 @@ class RedfishUtilsAuthTestCase(db_base.DbTestCase):
redfish_utils.get_system(self.node)
redfish_utils.get_system(self.node)
self.assertEqual(1, mock_sushy.call_count)
+ self.assertEqual(len(redfish_utils.SessionCache._sessions), 1)
@mock.patch.object(sushy, 'Sushy', autospec=True)
def test_ensure_new_session_address(self, mock_sushy):
@@ -270,6 +271,21 @@ class RedfishUtilsAuthTestCase(db_base.DbTestCase):
self.assertEqual(2, mock_sushy.call_count)
@mock.patch.object(sushy, 'Sushy', autospec=True)
+ def test_ensure_new_session_password(self, mock_sushy):
+ d_info = self.node.driver_info
+ d_info['redfish_username'] = 'foo'
+ d_info['redfish_password'] = 'bar'
+ self.node.driver_info = d_info
+ self.node.save()
+ redfish_utils.get_system(self.node)
+ d_info['redfish_password'] = 'foo'
+ self.node.driver_info = d_info
+ self.node.save()
+ redfish_utils.SessionCache._sessions = collections.OrderedDict()
+ redfish_utils.get_system(self.node)
+ self.assertEqual(2, mock_sushy.call_count)
+
+ @mock.patch.object(sushy, 'Sushy', autospec=True)
@mock.patch('ironic.drivers.modules.redfish.utils.'
'SessionCache.AUTH_CLASSES', autospec=True)
@mock.patch('ironic.drivers.modules.redfish.utils.SessionCache._sessions',