Use crypt to generate salt
Let's use the crypt to generate the salt, the crypt.crypt can handle the generation of the salt if we don't pass. Change-Id: I63fca663940e44924a201b166bdd79d8f7710bee Story: 2007443 Task: 39103
This commit is contained in:
parent
6f1f9c7f6e
commit
7f8afac092
@ -11,8 +11,6 @@
|
|||||||
# limitations under the License.
|
# limitations under the License.
|
||||||
|
|
||||||
import crypt
|
import crypt
|
||||||
import random
|
|
||||||
import string
|
|
||||||
|
|
||||||
from oslo_log import log
|
from oslo_log import log
|
||||||
|
|
||||||
@ -25,16 +23,6 @@ PASSWORD_FILE = '/etc/ipa-rescue-config/ipa-rescue-password'
|
|||||||
|
|
||||||
class RescueExtension(base.BaseAgentExtension):
|
class RescueExtension(base.BaseAgentExtension):
|
||||||
|
|
||||||
def make_salt(self):
|
|
||||||
"""Generate a random salt for hashing the rescue password.
|
|
||||||
|
|
||||||
Salt should be a two-character string from the set [a-zA-Z0-9].
|
|
||||||
|
|
||||||
:returns: a valid salt for use with crypt.crypt
|
|
||||||
"""
|
|
||||||
allowed_chars = string.ascii_letters + string.digits
|
|
||||||
return random.choice(allowed_chars) + random.choice(allowed_chars)
|
|
||||||
|
|
||||||
def write_rescue_password(self, rescue_password="", hashed=False):
|
def write_rescue_password(self, rescue_password="", hashed=False):
|
||||||
"""Write rescue password to a file for use after IPA exits.
|
"""Write rescue password to a file for use after IPA exits.
|
||||||
|
|
||||||
@ -55,8 +43,7 @@ class RescueExtension(base.BaseAgentExtension):
|
|||||||
if hashed:
|
if hashed:
|
||||||
hashed_password = password
|
hashed_password = password
|
||||||
else:
|
else:
|
||||||
salt = self.make_salt()
|
hashed_password = crypt.crypt(rescue_password)
|
||||||
hashed_password = crypt.crypt(rescue_password, salt)
|
|
||||||
try:
|
try:
|
||||||
with open(PASSWORD_FILE, 'w') as f:
|
with open(PASSWORD_FILE, 'w') as f:
|
||||||
f.write(hashed_password)
|
f.write(hashed_password)
|
||||||
|
@ -10,8 +10,6 @@
|
|||||||
# See the License for the specific language governing permissions and
|
# See the License for the specific language governing permissions and
|
||||||
# limitations under the License.
|
# limitations under the License.
|
||||||
|
|
||||||
import string
|
|
||||||
|
|
||||||
import mock
|
import mock
|
||||||
from oslotest import base as test_base
|
from oslotest import base as test_base
|
||||||
|
|
||||||
@ -26,25 +24,16 @@ class TestRescueExtension(test_base.BaseTestCase):
|
|||||||
self.agent_extension = rescue.RescueExtension()
|
self.agent_extension = rescue.RescueExtension()
|
||||||
self.agent_extension.agent = FakeAgent()
|
self.agent_extension.agent = FakeAgent()
|
||||||
|
|
||||||
def test_make_salt(self):
|
|
||||||
salt = self.agent_extension.make_salt()
|
|
||||||
self.assertEqual(2, len(salt))
|
|
||||||
for char in salt:
|
|
||||||
self.assertIn(char, string.ascii_letters + string.digits)
|
|
||||||
|
|
||||||
@mock.patch('ironic_python_agent.extensions.rescue.crypt.crypt',
|
@mock.patch('ironic_python_agent.extensions.rescue.crypt.crypt',
|
||||||
autospec=True)
|
autospec=True)
|
||||||
@mock.patch('ironic_python_agent.extensions.rescue.RescueExtension.'
|
def test_write_rescue_password(self, mock_crypt):
|
||||||
'make_salt', autospec=True)
|
|
||||||
def test_write_rescue_password(self, mock_salt, mock_crypt):
|
|
||||||
mock_salt.return_value = '12'
|
|
||||||
mock_crypt.return_value = '12deadbeef'
|
mock_crypt.return_value = '12deadbeef'
|
||||||
mock_open = mock.mock_open()
|
mock_open = mock.mock_open()
|
||||||
with mock.patch('ironic_python_agent.extensions.rescue.open',
|
with mock.patch('ironic_python_agent.extensions.rescue.open',
|
||||||
mock_open):
|
mock_open):
|
||||||
self.agent_extension.write_rescue_password('password')
|
self.agent_extension.write_rescue_password('password')
|
||||||
|
|
||||||
mock_crypt.assert_called_once_with('password', '12')
|
mock_crypt.assert_called_once_with('password')
|
||||||
mock_open.assert_called_once_with(
|
mock_open.assert_called_once_with(
|
||||||
'/etc/ipa-rescue-config/ipa-rescue-password', 'w')
|
'/etc/ipa-rescue-config/ipa-rescue-password', 'w')
|
||||||
file_handle = mock_open()
|
file_handle = mock_open()
|
||||||
@ -52,10 +41,7 @@ class TestRescueExtension(test_base.BaseTestCase):
|
|||||||
|
|
||||||
@mock.patch('ironic_python_agent.extensions.rescue.crypt.crypt',
|
@mock.patch('ironic_python_agent.extensions.rescue.crypt.crypt',
|
||||||
autospec=True)
|
autospec=True)
|
||||||
@mock.patch('ironic_python_agent.extensions.rescue.RescueExtension.'
|
def test_write_rescue_password_ioerror(self, mock_crypt):
|
||||||
'make_salt', autospec=True)
|
|
||||||
def test_write_rescue_password_ioerror(self, mock_salt, mock_crypt):
|
|
||||||
mock_salt.return_value = '12'
|
|
||||||
mock_crypt.return_value = '12deadbeef'
|
mock_crypt.return_value = '12deadbeef'
|
||||||
mock_open = mock.mock_open()
|
mock_open = mock.mock_open()
|
||||||
with mock.patch('ironic_python_agent.extensions.rescue.open',
|
with mock.patch('ironic_python_agent.extensions.rescue.open',
|
||||||
@ -68,16 +54,12 @@ class TestRescueExtension(test_base.BaseTestCase):
|
|||||||
|
|
||||||
@mock.patch('ironic_python_agent.extensions.rescue.crypt.crypt',
|
@mock.patch('ironic_python_agent.extensions.rescue.crypt.crypt',
|
||||||
autospec=True)
|
autospec=True)
|
||||||
@mock.patch('ironic_python_agent.extensions.rescue.RescueExtension.'
|
def _write_password_hashed_test(self, password, mock_crypt):
|
||||||
'make_salt', autospec=True)
|
|
||||||
def _write_password_hashed_test(self, password, mock_salt,
|
|
||||||
mock_crypt):
|
|
||||||
mock_open = mock.mock_open()
|
mock_open = mock.mock_open()
|
||||||
with mock.patch('ironic_python_agent.extensions.rescue.open',
|
with mock.patch('ironic_python_agent.extensions.rescue.open',
|
||||||
mock_open):
|
mock_open):
|
||||||
self.agent_extension.write_rescue_password(password,
|
self.agent_extension.write_rescue_password(password,
|
||||||
hashed=True)
|
hashed=True)
|
||||||
self.assertFalse(mock_salt.called)
|
|
||||||
self.assertFalse(mock_crypt.called)
|
self.assertFalse(mock_crypt.called)
|
||||||
mock_open.assert_called_once_with(
|
mock_open.assert_called_once_with(
|
||||||
'/etc/ipa-rescue-config/ipa-rescue-password', 'w')
|
'/etc/ipa-rescue-config/ipa-rescue-password', 'w')
|
||||||
|
@ -0,0 +1,9 @@
|
|||||||
|
---
|
||||||
|
security:
|
||||||
|
- |
|
||||||
|
The salt was generated using random and the module it's not in compliance
|
||||||
|
with FIPS 140-2. Now we let the salt be automatically generated by the
|
||||||
|
crypt function (it will use the strongest method available).
|
||||||
|
fixes:
|
||||||
|
- |
|
||||||
|
The salt now will be automatically generated by the crypt function.
|
Loading…
Reference in New Issue
Block a user