Allows users to retrieve ciphered VM passwords
This patch allows users to retrieve VM encrypted passwords using the `nova get-password` command without specifying the private key. Change-Id: I13ea132160dca912c6c1643b1006377982b778a1 Implements: blueprint retrieve-ciphered-vm-password
This commit is contained in:
parent
c51dc4a525
commit
fabbc87bf2
27
novaclient/tests/idfake.pem
Normal file
27
novaclient/tests/idfake.pem
Normal file
@ -0,0 +1,27 @@
|
||||
-----BEGIN RSA PRIVATE KEY-----
|
||||
MIIEowIBAAKCAQEA9QstF/7prDY7a9La7GS9TpMX+MWWXQgK6pHRLakDFp1WX1Q3
|
||||
Vly7rWitaZUGirUPMm181oJXBwkKlAxFD7hKjyHYaSswNszPYIAsVkc1+AO5epXz
|
||||
g9kUBNtfg44Pg72UecwLrZ8JpmNZpJlKQOx6vF+yi7JmHrrIf6il/grIGUPzoT2L
|
||||
yReimpyPoBrGtXhJYaCJ/XbKg1idRZiQdmwh1F/OmZWn9p0wunnsv08a0+qIywuw
|
||||
WhG9/Zy9fjnEByfusS6gI0GIxDRL4RWzOqphd3PZzunwIBgEKFhgiki9+2DgcRVO
|
||||
9I5wnDvfwQREJRZWh1uJa5ZTcfPa1EzZryVeOQIDAQABAoIBABxO3Te/cBk/7p9n
|
||||
LXlPrfrszUEk+ljm+/PbQpIGy1+Kb5b1sKrebaP7ysS+vZG6lvXZZimVxx398mXm
|
||||
APhu7tYYL9r+bUR3ZqGcTQLumRJ8w6mgtxANPN3Oxfr5p1stxIBJjTPSgpfhNFLq
|
||||
joRvjUJDv+mZg2ibZVwyDHMLpdAdKp+3XMdyTLZcH9esqwii+natix7rHd1RuF85
|
||||
L1dfpxjkItwhgHsfdYS++5X3fRByFOhQ+Nhabh/kPQbQMcteRn1bN6zeCWBSglNb
|
||||
Ka/ZrXb6ApRUc22Ji62mNO2ZPPekLJeCHk2h2E7ezYX+sGDNvvd/jHVDJJ20FjD1
|
||||
Z9KXuK0CgYEA/2vniy9yWd925QQtWbmrxgy6yj89feMH/LTv4qP298rGZ2nqxsyd
|
||||
9pdBdb4NMsi4HmV5PG1hp3VRNBHl53DNh5eqzT8WEXnIF+sbrIU3KzrCVAx1kZTl
|
||||
+OWKA6aVUsvvO3y85SOvInnsV+IsOGmU4/WBSjYoe39Bo7mq/YuZB9MCgYEA9ZlB
|
||||
KBm6PjFdHQGNgedXahWzRcwC+ALCYqequPYqJolNzhrK4Uc2sWPSGdnldcHZ4XCQ
|
||||
wbfCxUSwrMpA1oyuIQ0U4aowmOw5DjIueBWI8XBYEVRBlwvJwbXpBZ/DspGzTUDx
|
||||
MBrrEwEaMadQvxhRnAzhp0rQAepatcz6Fgb1JkMCgYBMwDLiew5kfSav6JJsDMPW
|
||||
DksurNQgeNEUmZYfx19V1EPMHWKj/CZXS9oqtEIpCXFyCNHmW4PlmvYcrGgmJJpN
|
||||
7UAwzo0mES8UKNy2+Yy7W7u7H8dQSKrWILtZH3xtVcR8Xp4wSIm+1V40hkz9YpSP
|
||||
71y7XQzLF1E1DnyYFZOVawKBgAFrmHfd5jjT2kD/sEzPBK9lXrsJmf7LLUqaw578
|
||||
NXQxmRSXDRNOcR+Hf0CNBQmwTE1EdGHaaTLw2cC2Drfu6lbgl31SmaNYwl+1pJUn
|
||||
MrqKtseq4BI6jDkljypsKRqQQyQwOvTXQwLCH9+nowzn3Bj17hwkj51jOJESlWOp
|
||||
OKO3AoGBALm+jjqyqX7gSnqK3FAumB8mlhv3yI1Wr1ctwe18mKfKbz17HxXRu9pF
|
||||
K/6e7WMCA1p+jhoE8gj1h2WBcH0nV2qt8Ye8gJBbCi4dhI08o4AfrIV47oZx1RlO
|
||||
qYcA1U9lyaODY5SL8+6PHOy5J/aYtuA+wvfEnWiCIdKQrhWetcn3
|
||||
-----END RSA PRIVATE KEY-----
|
@ -483,8 +483,27 @@ class FakeHTTPClient(base_client.HTTPClient):
|
||||
# Server password
|
||||
#
|
||||
|
||||
# Testing with the following password and key
|
||||
#
|
||||
# Clear password: FooBar123
|
||||
#
|
||||
# RSA Private Key: novaclient/tests/idfake.pem
|
||||
#
|
||||
# Encrypted password
|
||||
# OIuEuQttO8Rk93BcKlwHQsziDAnkAm/V6V8VPToA8ZeUaUBWwS0gwo2K6Y61Z96r
|
||||
# qG447iRz0uTEEYq3RAYJk1mh3mMIRVl27t8MtIecR5ggVVbz1S9AwXJQypDKl0ho
|
||||
# QFvhCBcMWPohyGewDJOhDbtuN1IoFI9G55ZvFwCm5y7m7B2aVcoLeIsJZE4PLsIw
|
||||
# /y5a6Z3/AoJZYGG7IH5WN88UROU3B9JZGFB2qtPLQTOvDMZLUhoPRIJeHiVSlo1N
|
||||
# tI2/++UsXVg3ow6ItqCJGgdNuGG5JB+bslDHWPxROpesEIHdczk46HCpHQN8f1sk
|
||||
# Hi/fmZZNQQqj1Ijq0caOIw==
|
||||
def get_servers_1234_os_server_password(self, **kw):
|
||||
return (200, {}, {'password': ''})
|
||||
return (200, {}, {'password':
|
||||
'OIuEuQttO8Rk93BcKlwHQsziDAnkAm/V6V8VPToA8ZeUaUBWwS0gwo2K6Y61Z96r'
|
||||
'qG447iRz0uTEEYq3RAYJk1mh3mMIRVl27t8MtIecR5ggVVbz1S9AwXJQypDKl0ho'
|
||||
'QFvhCBcMWPohyGewDJOhDbtuN1IoFI9G55ZvFwCm5y7m7B2aVcoLeIsJZE4PLsIw'
|
||||
'/y5a6Z3/AoJZYGG7IH5WN88UROU3B9JZGFB2qtPLQTOvDMZLUhoPRIJeHiVSlo1N'
|
||||
'tI2/++UsXVg3ow6ItqCJGgdNuGG5JB+bslDHWPxROpesEIHdczk46HCpHQN8f1sk'
|
||||
'Hi/fmZZNQQqj1Ijq0caOIw=='})
|
||||
|
||||
def delete_servers_1234_os_server_password(self, **kw):
|
||||
return (202, {}, None)
|
||||
|
@ -420,9 +420,35 @@ class ServersTest(utils.TestCase):
|
||||
self.assertEqual(cs.servers.get_console_output(s, length=50), success)
|
||||
cs.assert_called('POST', '/servers/1234/action')
|
||||
|
||||
# Testing password methods with the following password and key
|
||||
#
|
||||
# Clear password: FooBar123
|
||||
#
|
||||
# RSA Private Key: novaclient/tests/idfake.pem
|
||||
#
|
||||
# Encrypted password
|
||||
# OIuEuQttO8Rk93BcKlwHQsziDAnkAm/V6V8VPToA8ZeUaUBWwS0gwo2K6Y61Z96r
|
||||
# qG447iRz0uTEEYq3RAYJk1mh3mMIRVl27t8MtIecR5ggVVbz1S9AwXJQypDKl0ho
|
||||
# QFvhCBcMWPohyGewDJOhDbtuN1IoFI9G55ZvFwCm5y7m7B2aVcoLeIsJZE4PLsIw
|
||||
# /y5a6Z3/AoJZYGG7IH5WN88UROU3B9JZGFB2qtPLQTOvDMZLUhoPRIJeHiVSlo1N
|
||||
# tI2/++UsXVg3ow6ItqCJGgdNuGG5JB+bslDHWPxROpesEIHdczk46HCpHQN8f1sk
|
||||
# Hi/fmZZNQQqj1Ijq0caOIw==
|
||||
|
||||
def test_get_password(self):
|
||||
s = cs.servers.get(1234)
|
||||
self.assertEqual(s.get_password('/foo/id_rsa'), '')
|
||||
self.assertEqual(s.get_password('novaclient/tests/idfake.pem'),
|
||||
b'FooBar123')
|
||||
cs.assert_called('GET', '/servers/1234/os-server-password')
|
||||
|
||||
def test_get_password_without_key(self):
|
||||
s = cs.servers.get(1234)
|
||||
self.assertEqual(s.get_password(),
|
||||
'OIuEuQttO8Rk93BcKlwHQsziDAnkAm/V6V8VPToA8ZeUaUBWwS0gwo2K6Y61Z96r'
|
||||
'qG447iRz0uTEEYq3RAYJk1mh3mMIRVl27t8MtIecR5ggVVbz1S9AwXJQypDKl0ho'
|
||||
'QFvhCBcMWPohyGewDJOhDbtuN1IoFI9G55ZvFwCm5y7m7B2aVcoLeIsJZE4PLsIw'
|
||||
'/y5a6Z3/AoJZYGG7IH5WN88UROU3B9JZGFB2qtPLQTOvDMZLUhoPRIJeHiVSlo1N'
|
||||
'tI2/++UsXVg3ow6ItqCJGgdNuGG5JB+bslDHWPxROpesEIHdczk46HCpHQN8f1sk'
|
||||
'Hi/fmZZNQQqj1Ijq0caOIw==')
|
||||
cs.assert_called('GET', '/servers/1234/os-server-password')
|
||||
|
||||
def test_clear_password(self):
|
||||
|
@ -1635,6 +1635,10 @@ class ShellTest(utils.TestCase):
|
||||
self.run_command('get-password sample-server /foo/id_rsa')
|
||||
self.assert_called('GET', '/servers/1234/os-server-password')
|
||||
|
||||
def test_get_password_without_key(self):
|
||||
self.run_command('get-password sample-server')
|
||||
self.assert_called('GET', '/servers/1234/os-server-password')
|
||||
|
||||
def test_clear_password(self):
|
||||
self.run_command('clear-password sample-server')
|
||||
self.assert_called('DELETE', '/servers/1234/os-server-password')
|
||||
|
@ -74,11 +74,15 @@ class Server(base.Resource):
|
||||
"""
|
||||
return self.manager.get_spice_console(self, console_type)
|
||||
|
||||
def get_password(self, private_key):
|
||||
def get_password(self, private_key=None):
|
||||
"""
|
||||
Get password for a Server.
|
||||
|
||||
Returns the clear password of an instance if private_key is
|
||||
provided, returns the ciphered password otherwise.
|
||||
|
||||
:param private_key: Path to private key file for decryption
|
||||
(optional)
|
||||
"""
|
||||
return self.manager.get_password(self, private_key)
|
||||
|
||||
@ -497,24 +501,29 @@ class ServerManager(base.BootingManagerWithFind):
|
||||
return self._action('os-getSPICEConsole', server,
|
||||
{'type': console_type})[1]
|
||||
|
||||
def get_password(self, server, private_key):
|
||||
def get_password(self, server, private_key=None):
|
||||
"""
|
||||
Get password for an instance
|
||||
|
||||
Returns the clear password of an instance if private_key is
|
||||
provided, returns the ciphered password otherwise.
|
||||
|
||||
Requires that openssl is installed and in the path
|
||||
|
||||
:param server: The :class:`Server` (or its ID) to add an IP to.
|
||||
:param private_key: The private key to decrypt password
|
||||
(optional)
|
||||
"""
|
||||
|
||||
_resp, body = self.api.client.get("/servers/%s/os-server-password"
|
||||
% base.getid(server))
|
||||
if body and body.get('password'):
|
||||
ciphered_pw = body.get('password', '') if body else ''
|
||||
if private_key and ciphered_pw:
|
||||
try:
|
||||
return crypto.decrypt_password(private_key, body['password'])
|
||||
return crypto.decrypt_password(private_key, ciphered_pw)
|
||||
except Exception as exc:
|
||||
return '%sFailed to decrypt:\n%s' % (exc, body['password'])
|
||||
return ''
|
||||
return '%sFailed to decrypt:\n%s' % (exc, ciphered_pw)
|
||||
return ciphered_pw
|
||||
|
||||
def clear_password(self, server):
|
||||
"""
|
||||
|
@ -1867,7 +1867,12 @@ def do_get_spice_console(cs, args):
|
||||
@utils.arg('server', metavar='<server>', help='Name or ID of server.')
|
||||
@utils.arg('private_key',
|
||||
metavar='<private-key>',
|
||||
help='Private key (used locally to decrypt password).')
|
||||
help='Private key (used locally to decrypt password) (Optional). '
|
||||
'When specified, the command displays the clear (decrypted) VM '
|
||||
'password. When not specified, the ciphered VM password is '
|
||||
'displayed.',
|
||||
nargs='?',
|
||||
default=None)
|
||||
def do_get_password(cs, args):
|
||||
"""Get password for a server."""
|
||||
server = _find_server(cs, args.server)
|
||||
|
@ -1701,7 +1701,12 @@ def do_get_spice_console(cs, args):
|
||||
@utils.arg('server', metavar='<server>', help='Name or ID of server.')
|
||||
@utils.arg('private_key',
|
||||
metavar='<private-key>',
|
||||
help='Private key (used locally to decrypt password).')
|
||||
help='Private key (used locally to decrypt password) (Optional). '
|
||||
'When specified, the command displays the clear (decrypted) VM '
|
||||
'password. When not specified, the ciphered VM password is '
|
||||
'displayed.',
|
||||
nargs='?',
|
||||
default=None)
|
||||
def do_get_password(cs, args):
|
||||
"""Get password for a server."""
|
||||
server = _find_server(cs, args.server)
|
||||
|
Loading…
Reference in New Issue
Block a user