Add support for cert-based access type
This patch adds support for cert-based access type. The access_to parameter represents certificate's CN (aka common name) to which access is denied or allowed by the backend. Partially-implements blueprint cert-based-access-type Change-Id: I70c21397028e642bcf018ff254466046e38dcc3a
This commit is contained in:
parent
542b59e891
commit
157ddd088d
|
@ -61,14 +61,27 @@ class Share(common_base.Resource):
|
|||
self._validate_ip_range(access)
|
||||
elif access_type == 'user':
|
||||
self._validate_username(access)
|
||||
elif access_type == 'cert':
|
||||
# 'access' is used as the certificate's CN (common name)
|
||||
# to which access is allowed or denied by the backend.
|
||||
# The standard allows for just about any string in the
|
||||
# common name. The meaning of a string depends on its
|
||||
# interpretation and is limited to 64 characters.
|
||||
self._validate_common_name(access.strip())
|
||||
else:
|
||||
raise exceptions.CommandError(
|
||||
'Only ip and user type are supported')
|
||||
'Only ip, user, and cert types are supported')
|
||||
|
||||
def update_all_metadata(self, metadata):
|
||||
"""Update all metadata of this share."""
|
||||
return self.manager.update_all_metadata(self, metadata)
|
||||
|
||||
@staticmethod
|
||||
def _validate_common_name(access):
|
||||
if len(access) == 0 or len(access) > 64:
|
||||
exc_str = ('Invalid CN (common name). Must be 1-64 chars long.')
|
||||
raise exceptions.CommandError(exc_str)
|
||||
|
||||
@staticmethod
|
||||
def _validate_username(access):
|
||||
valid_useraname_re = '[\w\.\-_\`;\'\{\}\[\]]{4,32}$'
|
||||
|
|
|
@ -487,7 +487,7 @@ def do_show(cs, args):
|
|||
@cliutils.arg(
|
||||
'access_type',
|
||||
metavar='<access_type>',
|
||||
help='Access rule type (only "ip" and "user"(user or group) '
|
||||
help='Access rule type (only "ip", "user"(user or group), and "cert" '
|
||||
'are supported).')
|
||||
@cliutils.arg(
|
||||
'access_to',
|
||||
|
|
|
@ -15,6 +15,9 @@
|
|||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
import mock
|
||||
|
||||
from manilaclient import exceptions
|
||||
from manilaclient import extension
|
||||
from manilaclient.v1 import shares
|
||||
from tests import utils
|
||||
|
@ -29,6 +32,45 @@ cs = fakes.FakeClient(extensions=extensions)
|
|||
|
||||
class SharesTest(utils.TestCase):
|
||||
|
||||
# Testcases for class Share
|
||||
def setUp(self):
|
||||
super(SharesTest, self).setUp()
|
||||
self.share = shares.Share(None, {'id': 1})
|
||||
self.share.manager = mock.Mock()
|
||||
|
||||
def test_share_allow_access_cert(self):
|
||||
access_type = 'cert'
|
||||
access_to = 'client.example.com'
|
||||
|
||||
self.share.allow(access_type, access_to)
|
||||
|
||||
self.assertTrue(self.share.manager.allow.called)
|
||||
|
||||
def test_share_allow_access_cert_error_gt64(self):
|
||||
access_type = 'cert'
|
||||
access_to = 'x' * 65
|
||||
|
||||
self.assertRaises(exceptions.CommandError,
|
||||
self.share.allow, access_type, access_to)
|
||||
self.assertFalse(self.share.manager.allow.called)
|
||||
|
||||
def test_share_allow_access_cert_error_whitespace(self):
|
||||
access_type = 'cert'
|
||||
access_to = ' '
|
||||
|
||||
self.assertRaises(exceptions.CommandError,
|
||||
self.share.allow, access_type, access_to)
|
||||
self.assertFalse(self.share.manager.allow.called)
|
||||
|
||||
def test_share_allow_access_cert_error_zero(self):
|
||||
access_type = 'cert'
|
||||
access_to = ''
|
||||
|
||||
self.assertRaises(exceptions.CommandError,
|
||||
self.share.allow, access_type, access_to)
|
||||
self.assertFalse(self.share.manager.allow.called)
|
||||
|
||||
# Testcases for class ShareManager
|
||||
def test_create_nfs_share(self):
|
||||
cs.shares.create('nfs', 1)
|
||||
cs.assert_called('POST', '/shares')
|
||||
|
@ -58,6 +100,12 @@ class SharesTest(utils.TestCase):
|
|||
cs.shares.allow(share, 'ip', ip)
|
||||
cs.assert_called('POST', '/shares/1234/action')
|
||||
|
||||
def test_allow_access_to_share_with_cert(self):
|
||||
share = cs.shares.get(1234)
|
||||
common_name = 'test.example.com'
|
||||
cs.shares.allow(share, 'cert', common_name)
|
||||
cs.assert_called('POST', '/shares/1234/action')
|
||||
|
||||
def test_get_metadata(self):
|
||||
cs.shares.get_metadata(1234)
|
||||
cs.assert_called('GET', '/shares/1234/metadata')
|
||||
|
|
|
@ -301,6 +301,40 @@ class ShellTest(utils.TestCase):
|
|||
}
|
||||
self.assert_called("POST", "/shares", body=expected)
|
||||
|
||||
def test_allow_access_cert(self):
|
||||
self.run_command("access-allow 1234 cert client.example.com")
|
||||
|
||||
expected = {
|
||||
"os-allow_access": {
|
||||
"access_type": "cert",
|
||||
"access_to": "client.example.com",
|
||||
}
|
||||
}
|
||||
self.assert_called("POST", "/shares/1234/action", body=expected)
|
||||
|
||||
def test_allow_access_cert_error_gt64(self):
|
||||
common_name = 'x' * 65
|
||||
self.assertRaises(exceptions.CommandError, self.run_command,
|
||||
("access-allow 1234 cert %s" % common_name))
|
||||
|
||||
def test_allow_access_cert_error_zero(self):
|
||||
cmd = mock.Mock()
|
||||
cmd.split = mock.Mock(side_effect=lambda: ['access-allow', '1234',
|
||||
'cert', ''])
|
||||
|
||||
self.assertRaises(exceptions.CommandError, self.run_command, cmd)
|
||||
|
||||
cmd.split.assert_called_once_with()
|
||||
|
||||
def test_allow_access_cert_error_whitespace(self):
|
||||
cmd = mock.Mock()
|
||||
cmd.split = mock.Mock(side_effect=lambda: ['access-allow', '1234',
|
||||
'cert', ' '])
|
||||
|
||||
self.assertRaises(exceptions.CommandError, self.run_command, cmd)
|
||||
|
||||
cmd.split.assert_called_once_with()
|
||||
|
||||
@mock.patch.object(fakes.FakeClient, 'authenticate', mock.Mock())
|
||||
@mock.patch.object(shell.SecretsHelper, '_make_key', mock.Mock())
|
||||
@mock.patch.object(shell.SecretsHelper, 'password', mock.Mock())
|
||||
|
|
Loading…
Reference in New Issue