diff options
| author | Unmesh Gurjar <unmesh.gurjar@vertex.co.in> | 2012-04-03 11:45:22 +0530 |
|---|---|---|
| committer | Unmesh Gurjar <unmesh.gurjar@vertex.co.in> | 2012-05-09 12:10:09 +0530 |
| commit | b69dbc2f2748cf3261dce02057c60cdb7affd4ce (patch) | |
| tree | ede3ac89f151bef7bc48911b081a34dec32a8e94 | |
| parent | 2bf26cf47d650346fbe8c84701f19f36ed7b4624 (diff) | |
| download | keystone-b69dbc2f2748cf3261dce02057c60cdb7affd4ce.tar.gz keystone-b69dbc2f2748cf3261dce02057c60cdb7affd4ce.tar.xz keystone-b69dbc2f2748cf3261dce02057c60cdb7affd4ce.zip | |
Added tenant name validation. Fixes bug 966249.
1. Verified name length while creating/updating tenant (for all backends).
2. Disallowed blank tenant name in create/update.
3. Added unit test coverage.
Change-Id: Ied1e2707ba16e14d791308fb618ca18effa0245f
| -rw-r--r-- | keystone/clean.py | 44 | ||||
| -rw-r--r-- | keystone/identity/backends/kvs.py | 3 | ||||
| -rw-r--r-- | keystone/identity/backends/ldap/core.py | 4 | ||||
| -rw-r--r-- | keystone/identity/backends/sql.py | 6 | ||||
| -rw-r--r-- | tests/test_backend.py | 62 | ||||
| -rw-r--r-- | tests/test_backend_kvs.py | 1 | ||||
| -rw-r--r-- | tests/test_backend_sql.py | 2 |
7 files changed, 119 insertions, 3 deletions
diff --git a/keystone/clean.py b/keystone/clean.py new file mode 100644 index 00000000..e0bca179 --- /dev/null +++ b/keystone/clean.py @@ -0,0 +1,44 @@ +# vim: tabstop=4 shiftwidth=4 softtabstop=4 + +# Copyright 2012 OpenStack LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +from keystone import exception + + +def check_length(property_name, value, min_length=1, max_length=64): + if len(value) < min_length: + if min_length == 1: + msg = "%s cannot be empty." % property_name + else: + msg = ("%(property_name)s cannot be less than " + "%(min_length)s characters.") % locals() + raise exception.ValidationError(msg) + if len(value) > max_length: + msg = ("%(property_name)s should not be greater than " + "%(max_length)s characters.") % locals() + raise exception.ValidationError(msg) + + +def check_type(property_name, value, expected_type, display_expected_type): + if not isinstance(value, expected_type): + msg = "%(property_name)s is not a %(display_expected_type)s" % locals() + raise exception.ValidationError(msg) + + +def tenant_name(name): + check_type("Tenant name", name, basestring, "string or unicode") + name = name.strip() + check_length("Tenant name", name) + return name diff --git a/keystone/identity/backends/kvs.py b/keystone/identity/backends/kvs.py index 55bd8f08..589d8c45 100644 --- a/keystone/identity/backends/kvs.py +++ b/keystone/identity/backends/kvs.py @@ -14,6 +14,7 @@ # License for the specific language governing permissions and limitations # under the License. +from keystone import clean from keystone import exception from keystone import identity from keystone.common import kvs @@ -195,6 +196,7 @@ class Identity(kvs.Base, identity.Driver): return None def create_tenant(self, tenant_id, tenant): + tenant['name'] = clean.tenant_name(tenant['name']) if self.get_tenant(tenant_id): msg = 'Duplicate ID, %s.' % tenant_id raise exception.Conflict(type='tenant', details=msg) @@ -207,6 +209,7 @@ class Identity(kvs.Base, identity.Driver): def update_tenant(self, tenant_id, tenant): if 'name' in tenant: + tenant['name'] = clean.tenant_name(tenant['name']) existing = self.db.get('tenant_name-%s' % tenant['name']) if existing and tenant_id != existing['id']: msg = 'Duplicate name, %s.' % tenant['name'] diff --git a/keystone/identity/backends/ldap/core.py b/keystone/identity/backends/ldap/core.py index 14e0b5fd..8c3a5729 100644 --- a/keystone/identity/backends/ldap/core.py +++ b/keystone/identity/backends/ldap/core.py @@ -19,6 +19,7 @@ import uuid import ldap from ldap import filter as ldap_filter +from keystone import clean from keystone import config from keystone import exception from keystone import identity @@ -166,12 +167,15 @@ class Identity(identity.Driver): return self.user.update(user_id, user) def create_tenant(self, tenant_id, tenant): + tenant['name'] = clean.tenant_name(tenant['name']) data = tenant.copy() if 'id' not in data or data['id'] is None: data['id'] = str(uuid.uuid4().hex) return self.tenant.create(tenant) def update_tenant(self, tenant_id, tenant): + if 'name' in tenant: + tenant['name'] = clean.tenant_name(tenant['name']) return self.tenant.update(tenant_id, tenant) def create_metadata(self, user_id, tenant_id, metadata): diff --git a/keystone/identity/backends/sql.py b/keystone/identity/backends/sql.py index dd35d70b..c752dd0b 100644 --- a/keystone/identity/backends/sql.py +++ b/keystone/identity/backends/sql.py @@ -17,8 +17,9 @@ import copy import functools -from keystone import identity +from keystone import clean from keystone import exception +from keystone import identity from keystone.common import sql from keystone.common import utils from keystone.common.sql import migration @@ -341,6 +342,7 @@ class Identity(sql.Base, identity.Driver): @handle_conflicts(type='tenant') def create_tenant(self, tenant_id, tenant): + tenant['name'] = clean.tenant_name(tenant['name']) session = self.get_session() with session.begin(): tenant_ref = Tenant.from_dict(tenant) @@ -350,6 +352,8 @@ class Identity(sql.Base, identity.Driver): @handle_conflicts(type='tenant') def update_tenant(self, tenant_id, tenant): + if 'name' in tenant: + tenant['name'] = clean.tenant_name(tenant['name']) session = self.get_session() with session.begin(): tenant_ref = session.query(Tenant).filter_by(id=tenant_id).first() diff --git a/tests/test_backend.py b/tests/test_backend.py index d7079ba6..c5404ad3 100644 --- a/tests/test_backend.py +++ b/tests/test_backend.py @@ -303,6 +303,65 @@ class IdentityTests(object): tenants = self.identity_api.get_tenants_for_user('foo') self.assertIn(tenant_id, tenants) + def test_create_tenant_long_name_fails(self): + tenant = {'id': 'fake1', 'name': 'a' * 65} + self.assertRaises(exception.ValidationError, + self.identity_api.create_tenant, + tenant['id'], + tenant) + + def test_create_tenant_blank_name_fails(self): + tenant = {'id': 'fake1', 'name': ''} + self.assertRaises(exception.ValidationError, + self.identity_api.create_tenant, + tenant['id'], + tenant) + + def test_create_tenant_invalid_name_fails(self): + tenant = {'id': 'fake1', 'name': None} + self.assertRaises(exception.ValidationError, + self.identity_api.create_tenant, + tenant['id'], + tenant) + tenant = {'id': 'fake1', 'name': 123} + self.assertRaises(exception.ValidationError, + self.identity_api.create_tenant, + tenant['id'], + tenant) + + def test_update_tenant_blank_name_fails(self): + tenant = {'id': 'fake1', 'name': 'fake1'} + self.identity_api.create_tenant('fake1', tenant) + tenant['name'] = '' + self.assertRaises(exception.ValidationError, + self.identity_api.update_tenant, + tenant['id'], + tenant) + + def test_update_tenant_long_name_fails(self): + tenant = {'id': 'fake1', 'name': 'fake1'} + self.identity_api.create_tenant('fake1', tenant) + tenant['name'] = 'a' * 65 + self.assertRaises(exception.ValidationError, + self.identity_api.update_tenant, + tenant['id'], + tenant) + + def test_update_tenant_invalid_name_fails(self): + tenant = {'id': 'fake1', 'name': 'fake1'} + self.identity_api.create_tenant('fake1', tenant) + tenant['name'] = None + self.assertRaises(exception.ValidationError, + self.identity_api.update_tenant, + tenant['id'], + tenant) + + tenant['name'] = 123 + self.assertRaises(exception.ValidationError, + self.identity_api.update_tenant, + tenant['id'], + tenant) + class TokenTests(object): def test_token_crud(self): @@ -326,7 +385,8 @@ class TokenTests(object): def test_expired_token(self): token_id = uuid.uuid4().hex - expire_time = datetime.datetime.utcnow() - datetime.timedelta(minutes=1) + expire_time = datetime.datetime.utcnow() - datetime.timedelta( + minutes=1) data = {'id': token_id, 'a': 'b', 'expires': expire_time} data_ref = self.token_api.create_token(token_id, data) self.assertDictEqual(data_ref, data) diff --git a/tests/test_backend_kvs.py b/tests/test_backend_kvs.py index 6e2f0d4e..695fcd54 100644 --- a/tests/test_backend_kvs.py +++ b/tests/test_backend_kvs.py @@ -13,6 +13,7 @@ # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License. + from keystone import test from keystone.identity.backends import kvs as identity_kvs from keystone.token.backends import kvs as token_kvs diff --git a/tests/test_backend_sql.py b/tests/test_backend_sql.py index 9ccc7826..5cb04f16 100644 --- a/tests/test_backend_sql.py +++ b/tests/test_backend_sql.py @@ -70,7 +70,7 @@ class SqlIdentity(test.TestCase, test_backend.IdentityTests): def test_create_null_tenant_name(self): tenant = {'id': uuid.uuid4().hex, 'name': None} - self.assertRaises(exception.Conflict, + self.assertRaises(exception.ValidationError, self.identity_api.create_tenant, tenant['id'], tenant) |
