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:
Deepak C Shetty 2014-08-25 12:34:45 +00:00 committed by Ben Swartzlander
parent 542b59e891
commit 157ddd088d
4 changed files with 97 additions and 2 deletions

View File

@ -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}$'

View File

@ -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',

View File

@ -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')

View File

@ -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())