summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorZiad Sawalha <ziad.sawalha@rackspace.com>2011-07-13 14:03:12 -0700
committerZiad Sawalha <ziad.sawalha@rackspace.com>2011-07-13 14:03:12 -0700
commit3873d2a409882b5f9dddfe96aa26fe1f3645a54f (patch)
tree1465850cc68ba1b9045343f790bba2ea5097660b
parentd59fc3a22cfdc50715a3831b6bff202bfc079169 (diff)
parent0d8f222173ad23808561ff66d762f36aa04b92f1 (diff)
Merge pull request #95 from dolph/master
Added system test discovery to run_tests.py
-rwxr-xr-xbin/keystone6
-rwxr-xr-xbin/keystone-auth4
-rwxr-xr-xetc/keystone.conf14
-rw-r--r--keystone/config.py9
-rw-r--r--keystone/controllers/user.py27
-rwxr-xr-xkeystone/logic/service.py196
-rw-r--r--keystone/logic/types/atom.py2
-rwxr-xr-xkeystone/logic/types/auth.py28
-rw-r--r--keystone/logic/types/endpoint.py11
-rw-r--r--keystone/logic/types/fault.py30
-rw-r--r--keystone/logic/types/role.py2
-rw-r--r--keystone/logic/types/tenant.py49
-rwxr-xr-xkeystone/logic/types/user.py8
-rw-r--r--keystone/middleware/url.py2
-rw-r--r--keystone/routers/service.py (renamed from keystone/routers/public.py)6
-rwxr-xr-xkeystone/server.py21
-rw-r--r--keystone/test/run_tests.py10
-rw-r--r--keystone/test/system/__init__.py1
-rw-r--r--keystone/test/system/common.py98
-rw-r--r--keystone/test/system/test_request_specs.py58
-rw-r--r--keystone/test/unit/base.py6
-rwxr-xr-xkeystone/test/unit/test_authentication.py72
-rwxr-xr-xkeystone/test/unit/test_groups.py3
-rw-r--r--keystone/test/unit/test_urlrewritefilter.py3
-rwxr-xr-xkeystone/utils.py43
25 files changed, 407 insertions, 302 deletions
diff --git a/bin/keystone b/bin/keystone
index 1725ed25..fc29b735 100755
--- a/bin/keystone
+++ b/bin/keystone
@@ -69,12 +69,12 @@ if __name__ == '__main__':
config_file = config.find_config_file(options, args)
print "Using config file:", config_file
- # Load Public API server
+ # Load Service API server
server = wsgi.Server()
- server.start(app, int(conf['public_port']), conf['public_host'])
+ server.start(app, int(conf['service_port']), conf['service_host'])
print "Service API listening on %s:%s" % (
- conf['public_host'], conf['public_port'])
+ conf['service_host'], conf['service_port'])
# Load Admin API server
admin_server = wsgi.Server()
diff --git a/bin/keystone-auth b/bin/keystone-auth
index e7d25fe9..bd02217a 100755
--- a/bin/keystone-auth
+++ b/bin/keystone-auth
@@ -63,10 +63,10 @@ if __name__ == '__main__':
print "Using config file:", config_file
server = wsgi.Server()
- server.start(app, int(conf['public_port']), conf['public_host'])
+ server.start(app, int(conf['service_port']), conf['service_host'])
print "Service API listening on %s:%s" % (
- conf['public_host'], conf['public_port'])
+ conf['service_host'], conf['service_port'])
server.wait()
except RuntimeError, e:
diff --git a/etc/keystone.conf b/etc/keystone.conf
index a404435e..243f9158 100755
--- a/etc/keystone.conf
+++ b/etc/keystone.conf
@@ -26,10 +26,10 @@ service-header-mappings = {
# Address to bind the API server
# TODO Properties defined within app not available via pipeline.
-public_host = 0.0.0.0
+service_host = 0.0.0.0
# Port the bind the API server to
-public_port = 5000
+service_port = 5000
# Address to bind the Admin API server
admin_host = 0.0.0.0
@@ -65,18 +65,18 @@ sql_idle_timeout = 30
[pipeline:admin]
pipeline =
urlrewritefilter
- admin_service
+ admin_api
[pipeline:keystone-legacy-auth]
pipeline =
urlrewritefilter
legacy_auth
- public_service
+ service_api
-[app:public_service]
-paste.app_factory = keystone.server:app_factory
+[app:service_api]
+paste.app_factory = keystone.server:service_app_factory
-[app:admin_service]
+[app:admin_api]
paste.app_factory = keystone.server:admin_app_factory
[filter:urlrewritefilter]
diff --git a/keystone/config.py b/keystone/config.py
index 30f408bb..c777fbad 100644
--- a/keystone/config.py
+++ b/keystone/config.py
@@ -1,5 +1,10 @@
-from keystone.logic.service import IdentityService
-
VERSION_STATUS = "ALPHA"
VERSION_DATE = "2011-04-23T00:00:00Z"
+
+from keystone.logic.service import IdentityService
SERVICE = IdentityService()
+
+# These just need to be imported somewhere, nothing appears to access them
+from keystone.backends import alterdb, sqlalchemy
+ALTERDB = alterdb
+SQLALCHEMY = sqlalchemy
diff --git a/keystone/controllers/user.py b/keystone/controllers/user.py
index 30b5dba9..18f28b69 100644
--- a/keystone/controllers/user.py
+++ b/keystone/controllers/user.py
@@ -19,8 +19,8 @@ class UserController(wsgi.Controller):
@utils.wrap_error
def get_users(self, req):
marker, limit, url = get_marker_limit_and_url(req)
- users = config.SERVICE.get_users(utils.get_auth_token(req), marker, limit,
- url)
+ users = config.SERVICE.get_users(utils.get_auth_token(req), marker,
+ limit, url)
return utils.send_result(200, req, users)
@utils.wrap_error
@@ -31,7 +31,8 @@ class UserController(wsgi.Controller):
@utils.wrap_error
def update_user(self, req, user_id):
user = utils.get_normalized_request_content(User_Update, req)
- rval = config.SERVICE.update_user(utils.get_auth_token(req), user_id, user)
+ rval = config.SERVICE.update_user(utils.get_auth_token(req), user_id,
+ user)
return utils.send_result(200, req, rval)
@utils.wrap_error
@@ -42,34 +43,34 @@ class UserController(wsgi.Controller):
@utils.wrap_error
def set_user_password(self, req, user_id):
user = utils.get_normalized_request_content(User_Update, req)
- rval = config.SERVICE.set_user_password(utils.get_auth_token(req), user_id,
- user)
+ rval = config.SERVICE.set_user_password(utils.get_auth_token(req),
+ user_id, user)
return utils.send_result(200, req, rval)
@utils.wrap_error
def set_user_enabled(self, req, user_id):
user = utils.get_normalized_request_content(User_Update, req)
- rval = config.SERVICE.enable_disable_user(utils.get_auth_token(req), user_id,
- user)
+ rval = config.SERVICE.enable_disable_user(utils.get_auth_token(req),
+ user_id, user)
return utils.send_result(200, req, rval)
@utils.wrap_error
def update_user_tenant(self, req, user_id):
user = utils.get_normalized_request_content(User_Update, req)
- rval = config.SERVICE.set_user_tenant(utils.get_auth_token(req), user_id,
- user)
+ rval = config.SERVICE.set_user_tenant(utils.get_auth_token(req),
+ user_id, user)
return utils.send_result(200, req, rval)
@utils.wrap_error
def get_tenant_users(self, req, tenant_id):
marker, limit, url = get_marker_limit_and_url(req)
- users = config.SERVICE.get_tenant_users(utils.get_auth_token(req), tenant_id,
- marker, limit, url)
+ users = config.SERVICE.get_tenant_users(utils.get_auth_token(req),
+ tenant_id, marker, limit, url)
return utils.send_result(200, req, users)
@utils.wrap_error
def get_user_groups(self, req, user_id):
marker, limit, url = get_marker_limit_and_url(req)
- groups = config.SERVICE.get_user_groups(utils.get_auth_token(req), user_id,
- marker, limit, url)
+ groups = config.SERVICE.get_user_groups(utils.get_auth_token(req),
+ user_id, marker, limit, url)
return utils.send_result(200, req, groups)
diff --git a/keystone/logic/service.py b/keystone/logic/service.py
index db49d5e1..fa032f4e 100755
--- a/keystone/logic/service.py
+++ b/keystone/logic/service.py
@@ -16,16 +16,17 @@
from datetime import datetime, timedelta
import uuid
-import keystone.logic.types.auth as auth
-import keystone.logic.types.atom as atom
+from keystone.logic.types import auth, atom
import keystone.backends as backends
import keystone.backends.api as api
import keystone.backends.models as models
-import keystone.logic.types.fault as fault
-import keystone.logic.types.tenant as tenants
-import keystone.logic.types.role as roles
-import keystone.logic.types.user as get_users
-import keystone.logic.types.endpoint as endpoints
+from keystone.logic.types import fault
+from keystone.logic.types.tenant import GlobalGroup, GlobalGroups, Group, \
+ Groups, Tenant, Tenants, User as TenantUser
+from keystone.logic.types.role import Role, RoleRef, RoleRefs, Roles
+from keystone.logic.types.user import User, User_Update, Users
+from keystone.logic.types.endpoint import Endpoint, Endpoints, \
+ EndpointTemplate, EndpointTemplates
import keystone.utils as utils
@@ -64,12 +65,9 @@ class IdentityService(object):
else:
dtoken = api.token.get_for_user_by_tenant(duser.id,
credentials.tenant_id)
- tenant_id = None
- if credentials.tenant_id:
- tenant_id = credentials.tenant_id
- else:
- tenant_id = duser.tenant_id
-
+
+ tenant_id = credentials.tenant_id or duser.tenant_id
+
if not dtoken or dtoken.expires < datetime.now():
# Create new token
dtoken = models.Token()
@@ -114,7 +112,7 @@ class IdentityService(object):
def create_tenant(self, admin_token, tenant):
self.__validate_token(admin_token)
- if not isinstance(tenant, tenants.Tenant):
+ if not isinstance(tenant, Tenant):
raise fault.BadRequestFault("Expecting a Tenant")
if tenant.tenant_id == None:
@@ -137,12 +135,12 @@ class IdentityService(object):
##
def get_tenants(self, admin_token, marker, limit, url):
try:
- (token, user) = self.__validate_token(admin_token)
- # If Global admin return all tenants.
+ (_token, user) = self.__validate_token(admin_token)
+ # If Global admin return all
ts = []
dtenants = api.tenant.get_page(marker, limit)
for dtenant in dtenants:
- ts.append(tenants.Tenant(dtenant.id,
+ ts.append(Tenant(dtenant.id,
dtenant.desc, dtenant.enabled))
prev, next = api.tenant.get_page_markers(marker, limit)
links = []
@@ -152,15 +150,15 @@ class IdentityService(object):
if next:
links.append(atom.Link('next', "%s?'marker=%s&limit=%s'" \
% (url, next, limit)))
- return tenants.Tenants(ts, links)
+ return Tenants(ts, links)
except fault.UnauthorizedFault:
#If not global admin ,return tenants specific to user.
- (token, user) = self.__validate_token(admin_token, False)
+ (_token, user) = self.__validate_token(admin_token, False)
ts = []
dtenants = api.tenant.tenants_for_user_get_page(\
user, marker, limit)
for dtenant in dtenants:
- ts.append(tenants.Tenant(dtenant.id,
+ ts.append(Tenant(dtenant.id,
dtenant.desc, dtenant.enabled))
prev, next = api.tenant.tenants_for_user_get_page_markers(\
user, marker, limit)
@@ -171,7 +169,7 @@ class IdentityService(object):
if next:
links.append(atom.Link('next', "%s?'marker=%s&limit=%s'" \
% (url, next, limit)))
- return tenants.Tenants(ts, links)
+ return Tenants(ts, links)
def get_tenant(self, admin_token, tenant_id):
self.__validate_token(admin_token)
@@ -179,12 +177,12 @@ class IdentityService(object):
dtenant = api.tenant.get(tenant_id)
if not dtenant:
raise fault.ItemNotFoundFault("The tenant could not be found")
- return tenants.Tenant(dtenant.id, dtenant.desc, dtenant.enabled)
+ return Tenant(dtenant.id, dtenant.desc, dtenant.enabled)
def update_tenant(self, admin_token, tenant_id, tenant):
self.__validate_token(admin_token)
- if not isinstance(tenant, tenants.Tenant):
+ if not isinstance(tenant, Tenant):
raise fault.BadRequestFault("Expecting a Tenant")
dtenant = api.tenant.get(tenant_id)
@@ -192,7 +190,7 @@ class IdentityService(object):
raise fault.ItemNotFoundFault("The tenant cloud not be found")
values = {'desc': tenant.description, 'enabled': tenant.enabled}
api.tenant.update(tenant_id, values)
- return tenants.Tenant(dtenant.id, tenant.description, tenant.enabled)
+ return Tenant(dtenant.id, tenant.description, tenant.enabled)
def delete_tenant(self, admin_token, tenant_id):
self.__validate_token(admin_token)
@@ -215,7 +213,7 @@ class IdentityService(object):
def create_tenant_group(self, admin_token, tenant, group):
self.__validate_token(admin_token)
- if not isinstance(group, tenants.Group):
+ if not isinstance(group, Group):
raise fault.BadRequestFault("Expecting a Group")
if tenant == None:
@@ -237,7 +235,7 @@ class IdentityService(object):
dtenant.desc = group.description
dtenant.tenant_id = tenant
api.tenant_group.create(dtenant)
- return tenants.Group(dtenant.id, dtenant.desc, dtenant.tenant_id)
+ return Group(dtenant.id, dtenant.desc, dtenant.tenant_id)
def get_tenant_groups(self, admin_token, tenant_id, marker, limit, url):
self.__validate_token(admin_token)
@@ -252,7 +250,7 @@ class IdentityService(object):
dtenantgroups = api.tenant_group.get_page(tenant_id, marker, limit)
for dtenantgroup in dtenantgroups:
- ts.append(tenants.Group(dtenantgroup.id,
+ ts.append(Group(dtenantgroup.id,
dtenantgroup.desc,
dtenantgroup.tenant_id))
prev, next = api.tenant_group.get_page_markers(tenant_id, marker,
@@ -265,7 +263,7 @@ class IdentityService(object):
links.append(atom.Link('next', "%s?'marker=%s&limit=%s'"\
% (url, next, limit)))
- return tenants.Groups(ts, links)
+ return Groups(ts, links)
def get_tenant_group(self, admin_token, tenant_id, group_id):
self.__validate_token(admin_token)
@@ -278,12 +276,12 @@ class IdentityService(object):
if not dtenant:
raise fault.ItemNotFoundFault("The tenant group not found")
- return tenants.Group(dtenant.id, dtenant.desc, dtenant.tenant_id)
+ return Group(dtenant.id, dtenant.desc, dtenant.tenant_id)
def update_tenant_group(self, admin_token, tenant_id, group_id, group):
self.__validate_token(admin_token)
- if not isinstance(group, tenants.Group):
+ if not isinstance(group, Group):
raise fault.BadRequestFault("Expecting a Group")
True
@@ -307,7 +305,7 @@ class IdentityService(object):
api.tenant_group.update(group_id, tenant_id, values)
- return tenants.Group(group_id, group.description, tenant_id)
+ return Group(group_id, group.description, tenant_id)
def delete_tenant_group(self, admin_token, tenant_id, group_id):
self.__validate_token(admin_token)
@@ -343,11 +341,15 @@ class IdentityService(object):
ts = []
dgroupusers = api.user.users_tenant_group_get_page(groupId, marker,
limit)
- for dgroupuser, dgroupuserAsso in dgroupusers:
-
- ts.append(tenants.User(dgroupuser.id,
- dgroupuser.email, dgroupuser.enabled,
- tenantId, None))
+ for dgroupuser, _dgroupuserAsso in dgroupusers:
+ # TODO: TenantUser is deprecated, and a near-duplicate of
+ # keystone.logic.types.user.User
+ ts.append(TenantUser(
+ user_id=dgroupuser.id,
+ email=dgroupuser.email,
+ enabled=dgroupuser.enabled,
+ tenant_id=tenantId,
+ group_id=None))
links = []
if ts.__len__():
prev, next = api.user.users_tenant_group_get_page_markers(
@@ -358,7 +360,7 @@ class IdentityService(object):
if next:
links.append(atom.Link('next', "%s?'marker=%s&limit=%s'" %
(url, next, limit)))
- return tenants.Users(ts, links)
+ return Users(ts, links)
def add_user_tenant_group(self, admin_token, tenant, group, user):
self.__validate_token(admin_token)
@@ -384,9 +386,15 @@ class IdentityService(object):
dusergroup.user_id = user
dusergroup.group_id = group
api.user.tenant_group(dusergroup)
-
- return tenants.User(duser.id, duser.email, duser.enabled,
- tenant, group)
+
+ # TODO: TenantUser is deprecated, and a near-duplicate of
+ # keystone.logic.types.user.User
+ return TenantUser(
+ user_id=duser.id,
+ email=duser.email,
+ enabled=duser.enabled,
+ tenant_id=tenant,
+ group_id=group) #attribute no longer exists
def delete_user_tenant_group(self, admin_token, tenant, group, user):
self.__validate_token(admin_token)
@@ -433,7 +441,7 @@ class IdentityService(object):
dtenant = self.validate_and_fetch_user_tenant(user.tenant_id)
- if not isinstance(user, get_users.User):
+ if not isinstance(user, User):
raise fault.BadRequestFault("Expecting a User")
if user.user_id == None:
@@ -483,7 +491,7 @@ class IdentityService(object):
dtenantusers = api.user.users_get_by_tenant_get_page(tenant_id, marker,
limit)
for dtenantuser in dtenantusers:
- ts.append(get_users.User(None, dtenantuser.id, tenant_id,
+ ts.append(User(None, dtenantuser.id, tenant_id,
dtenantuser.email, dtenantuser.enabled))
links = []
if ts.__len__():
@@ -495,14 +503,14 @@ class IdentityService(object):
if next:
links.append(atom.Link('next', "%s?'marker=%s&limit=%s'" %
(url, next, limit)))
- return get_users.Users(ts, links)
+ return Users(ts, links)
def get_users(self, admin_token, marker, limit, url):
self.__validate_token(admin_token)
ts = []
dusers = api.user.users_get_page(marker, limit)
for duser in dusers:
- ts.append(get_users.User(None, duser.id, duser.tenant_id,
+ ts.append(User(None, duser.id, duser.tenant_id,
duser.email, duser.enabled))
links = []
if ts.__len__():
@@ -513,7 +521,7 @@ class IdentityService(object):
if next:
links.append(atom.Link('next', "%s?'marker=%s&limit=%s'" %
(url, next, limit)))
- return get_users.Users(ts, links)
+ return Users(ts, links)
def get_user(self, admin_token, user_id):
self.__validate_token(admin_token)
@@ -529,10 +537,10 @@ class IdentityService(object):
ts = []
dusergroups = api.user.user_groups_get_all(user_id)
- for dusergroup, dusergroupAsso in dusergroups:
- ts.append(tenants.Group(dusergroup.id, dusergroup.tenant_id, None))
+ for dusergroup, _dusergroupAsso in dusergroups:
+ ts.append(Group(dusergroup.id, dusergroup.tenant_id, None))
- return get_users.User_Update(None, duser.id, duser.tenant_id,
+ return User_Update(None, duser.id, duser.tenant_id,
duser.email, duser.enabled, ts)
def update_user(self, admin_token, user_id, user):
@@ -546,7 +554,7 @@ class IdentityService(object):
if not duser.enabled:
raise fault.UserDisabledFault("User has been disabled")
- if not isinstance(user, get_users.User):
+ if not isinstance(user, User):
raise fault.BadRequestFault("Expecting a User")
if user.email != duser.email and \
@@ -557,7 +565,7 @@ class IdentityService(object):
values = {'email': user.email}
api.user.update(user_id, values)
duser = api.user.user_get_update(user_id)
- return get_users.User(duser.password, duser.id, duser.tenant_id,
+ return User(duser.password, duser.id, duser.tenant_id,
duser.email, duser.enabled)
def set_user_password(self, admin_token, user_id, user):
@@ -570,7 +578,7 @@ class IdentityService(object):
if not duser.enabled:
raise fault.UserDisabledFault("User has been disabled")
- if not isinstance(user, get_users.User):
+ if not isinstance(user, User):
raise fault.BadRequestFault("Expecting a User")
duser = api.user.get(user_id)
@@ -581,7 +589,7 @@ class IdentityService(object):
api.user.update(user_id, values)
- return get_users.User_Update(user.password,
+ return User_Update(user.password,
None, None, None, None, None)
def enable_disable_user(self, admin_token, user_id, user):
@@ -589,7 +597,7 @@ class IdentityService(object):
duser = api.user.get(user_id)
if not duser:
raise fault.ItemNotFoundFault("The user could not be found")
- if not isinstance(user, get_users.User):
+ if not isinstance(user, User):
raise fault.BadRequestFault("Expecting a User")
duser = api.user.get(user_id)
@@ -600,7 +608,7 @@ class IdentityService(object):
api.user.update(user_id, values)
- return get_users.User_Update(None,
+ return User_Update(None,
None, None, None, user.enabled, None)
def set_user_tenant(self, admin_token, user_id, user):
@@ -608,7 +616,7 @@ class IdentityService(object):
duser = api.user.get(user_id)
if not duser:
raise fault.ItemNotFoundFault("The user could not be found")
- if not isinstance(user, get_users.User):
+ if not isinstance(user, User):
raise fault.BadRequestFault("Expecting a User")
duser = api.user.get(user_id)
@@ -618,7 +626,7 @@ class IdentityService(object):
dtenant = self.validate_and_fetch_user_tenant(user.tenant_id)
values = {'tenant_id': user.tenant_id}
api.user.update(user_id, values)
- return get_users.User_Update(None,
+ return User_Update(None,
None, user.tenant_id, None, None, None)
def delete_user(self, admin_token, user_id):
@@ -641,8 +649,8 @@ class IdentityService(object):
dusergroups = api.group.get_by_user_get_page(user_id, marker,
limit)
- for dusergroup, dusergroupAsso in dusergroups:
- ts.append(tenants.Group(dusergroup.id, dusergroup.desc,
+ for dusergroup, _dusergroupAsso in dusergroups:
+ ts.append(Group(dusergroup.id, dusergroup.desc,
dusergroup.tenant_id))
links = []
if ts.__len__():
@@ -654,7 +662,7 @@ class IdentityService(object):
if next:
links.append(atom.Link('next', "%s?'marker=%s&limit=%s'" %
(url, next, limit)))
- return tenants.Groups(ts, links)
+ return Groups(ts, links)
#
# Global Group Operations
@@ -676,7 +684,7 @@ class IdentityService(object):
def create_global_group(self, admin_token, group):
self.__validate_token(admin_token)
- if not isinstance(group, tenants.GlobalGroup):
+ if not isinstance(group, GlobalGroup):
raise fault.BadRequestFault("Expecting a Group")
if group.group_id == None:
@@ -691,7 +699,7 @@ class IdentityService(object):
dtenant.desc = group.description
dtenant.tenant_id = gtenant.id
api.tenant_group.create(dtenant)
- return tenants.GlobalGroup(dtenant.id, dtenant.desc, None)
+ return GlobalGroup(dtenant.id, dtenant.desc, None)
def get_global_groups(self, admin_token, marker, limit, url):
self.__validate_token(admin_token)
@@ -700,7 +708,7 @@ class IdentityService(object):
dtenantgroups = api.tenant_group.get_page(gtenant.id, \
marker, limit)
for dtenantgroup in dtenantgroups:
- ts.append(tenants.GlobalGroup(dtenantgroup.id,
+ ts.append(GlobalGroup(dtenantgroup.id,
dtenantgroup.desc))
prev, next = api.tenant_group.get_page_markers(gtenant.id,
marker, limit)
@@ -711,7 +719,7 @@ class IdentityService(object):
if next:
links.append(atom.Link('next', "%s?'marker=%s&limit=%s'" %
(url, next, limit)))
- return tenants.GlobalGroups(ts, links)
+ return GlobalGroups(ts, links)
def get_global_group(self, admin_token, group_id):
self.__validate_token(admin_token)
@@ -724,12 +732,12 @@ class IdentityService(object):
if not dtenant:
raise fault.ItemNotFoundFault("The Global tenant group not found")
- return tenants.GlobalGroup(dtenant.id, dtenant.desc)
+ return GlobalGroup(dtenant.id, dtenant.desc)
def update_global_group(self, admin_token, group_id, group):
self.__validate_token(admin_token)
gtenant = self.__check_create_global_tenant()
- if not isinstance(group, tenants.GlobalGroup):
+ if not isinstance(group, GlobalGroup):
raise fault.BadRequestFault("Expecting a Group")
dtenant = api.tenant.get(gtenant.id)
@@ -745,7 +753,7 @@ class IdentityService(object):
values = {'desc': group.description}
api.tenant_group.update(group_id, gtenant.id, values)
- return tenants.GlobalGroup(group_id, group.description, gtenant.id)
+ return GlobalGroup(group_id, group.description, gtenant.id)
def delete_global_group(self, admin_token, group_id):
self.__validate_token(admin_token)
@@ -782,9 +790,13 @@ class IdentityService(object):
ts = []
dgroupusers = api.user.users_tenant_group_get_page(groupId, marker,
limit)
- for dgroupuser, dgroupuserassoc in dgroupusers:
- ts.append(tenants.User(dgroupuser.id, dgroupuser.email,
- dgroupuser.enabled))
+ for dgroupuser, _dgroupuserassoc in dgroupusers:
+ # TODO: TenantUser is deprecated, and a near-duplicate of
+ # keystone.logic.types.user.User
+ ts.append(TenantUser(
+ user_id=dgroupuser.id,
+ email=dgroupuser.email,
+ enabled=dgroupuser.enabled))
links = []
if ts.__len__():
prev, next = api.user.users_tenant_group_get_page_markers(groupId,
@@ -795,7 +807,7 @@ class IdentityService(object):
if next:
links.append(atom.Link('next', "%s?'marker=%s&limit=%s'"
% (url, next, limit)))
- return tenants.Users(ts, links)
+ return Users(ts, links)
def add_user_global_group(self, admin_token, group, user):
self.__validate_token(admin_token)
@@ -823,8 +835,13 @@ class IdentityService(object):
dusergroup.group_id = group
api.user.tenant_group(dusergroup)
- return tenants.User(duser.id, duser.email, duser.enabled,
- group_id=group)
+ # TODO: TenantUser is deprecated, and a near-duplicate of
+ # keystone.logic.types.user.User
+ return TenantUser(
+ user_id=duser.id,
+ email=duser.email,
+ enabled=duser.enabled,
+ group_id=group) # attribute no longer exists!
def delete_user_global_group(self, admin_token, group, user):
self.__validate_token(admin_token)
@@ -867,13 +884,13 @@ class IdentityService(object):
droleRefs = api.role.ref_get_all_tenant_roles(duser.id,
dtoken.tenant_id)
for droleRef in droleRefs:
- ts.append(roles.RoleRef(droleRef.id, droleRef.role_id,
+ ts.append(RoleRef(droleRef.id, droleRef.role_id,
droleRef.tenant_id))
droleRefs = api.role.ref_get_all_global_roles(duser.id)
for droleRef in droleRefs:
- ts.append(roles.RoleRef(droleRef.id, droleRef.role_id,
+ ts.append(RoleRef(droleRef.id, droleRef.role_id,
droleRef.tenant_id))
- user = auth.User(duser.id, duser.tenant_id, None, roles.RoleRefs(ts,
+ user = auth.User(duser.id, duser.tenant_id, None, RoleRefs(ts,
[]))
return auth.ValidateData(token, user)
@@ -902,7 +919,7 @@ class IdentityService(object):
def create_role(self, admin_token, role):
self.__validate_token(admin_token)
- if not isinstance(role, roles.Role):
+ if not isinstance(role, Role):
raise fault.BadRequestFault("Expecting a Role")
if role.role_id == None:
@@ -923,7 +940,7 @@ class IdentityService(object):
ts = []
droles = api.role.get_page(marker, limit)
for drole in droles:
- ts.append(roles.Role(drole.id,
+ ts.append(Role(drole.id,
drole.desc))
prev, next = api.role.get_page_markers(marker, limit)
links = []
@@ -933,7 +950,7 @@ class IdentityService(object):
if next:
links.append(atom.Link('next', "%s?'marker=%s&limit=%s'" \
% (url, next, limit)))
- return roles.Roles(ts, links)
+ return Roles(ts, links)
def get_role(self, admin_token, role_id):
self.__validate_token(admin_token)
@@ -941,7 +958,7 @@ class IdentityService(object):
drole = api.role.get(role_id)
if not drole:
raise fault.ItemNotFoundFault("The role could not be found")
- return roles.Role(drole.id, drole.desc)
+ return Role(drole.id, drole.desc)
def create_role_ref(self, admin_token, user_id, roleRef):
self.__validate_token(admin_token)
@@ -950,7 +967,7 @@ class IdentityService(object):
if not duser:
raise fault.ItemNotFoundFault("The user could not be found")
- if not isinstance(roleRef, roles.RoleRef):
+ if not isinstance(roleRef, RoleRef):
raise fault.BadRequestFault("Expecting a Role Ref")
if roleRef.role_id == None:
@@ -989,7 +1006,7 @@ class IdentityService(object):
ts = []
droleRefs = api.role.ref_get_page(marker, limit, user_id)
for droleRef in droleRefs:
- ts.append(roles.RoleRef(droleRef.id, droleRef.role_id,
+ ts.append(RoleRef(droleRef.id, droleRef.role_id,
droleRef.tenant_id))
prev, next = api.role.ref_get_page_markers(user_id, marker, limit)
links = []
@@ -999,7 +1016,7 @@ class IdentityService(object):
if next:
links.append(atom.Link('next', "%s?'marker=%s&limit=%s'" \
% (url, next, limit)))
- return roles.RoleRefs(ts, links)
+ return RoleRefs(ts, links)
def get_endpoint_templates(self, admin_token, marker, limit, url):
self.__validate_token(admin_token)
@@ -1007,7 +1024,7 @@ class IdentityService(object):
ts = []
dendpointTemplates = api.endpoint_template.get_page(marker, limit)
for dendpointTemplate in dendpointTemplates:
- ts.append(endpoints.EndpointTemplate(
+ ts.append(EndpointTemplate(
dendpointTemplate.id,
dendpointTemplate.region,
dendpointTemplate.service,
@@ -1024,7 +1041,7 @@ class IdentityService(object):
if next:
links.append(atom.Link('next', "%s?'marker=%s&limit=%s'" \
% (url, next, limit)))
- return endpoints.EndpointTemplates(ts, links)
+ return EndpointTemplates(ts, links)
def get_endpoint_template(self, admin_token, endpoint_template_id):
self.__validate_token(admin_token)
@@ -1033,7 +1050,7 @@ class IdentityService(object):
if not dendpointTemplate:
raise fault.ItemNotFoundFault(
"The endpoint template could not be found")
- return endpoints.EndpointTemplate(
+ return EndpointTemplate(
dendpointTemplate.id,
dendpointTemplate.region,
dendpointTemplate.service,
@@ -1058,7 +1075,7 @@ class IdentityService(object):
endpoint_get_by_tenant_get_page(
tenant_id, marker, limit)
for dtenantEndpoint in dtenantEndpoints:
- ts.append(endpoints.Endpoint(dtenantEndpoint.id,
+ ts.append(Endpoint(dtenantEndpoint.id,
url + '/endpointTemplates/' + \
str(dtenantEndpoint.endpoint_template_id)))
links = []
@@ -1072,7 +1089,7 @@ class IdentityService(object):
if next:
links.append(atom.Link('next', "%s?'marker=%s&limit=%s'" %
(url, next, limit)))
- return endpoints.Endpoints(ts, links)
+ return Endpoints(ts, links)
def create_endpoint_for_tenant(self, admin_token,
tenant_id, endpoint_template, url):
@@ -1090,9 +1107,8 @@ class IdentityService(object):
dendpoint.tenant_id = tenant_id
dendpoint.endpoint_template_id = endpoint_template.id
dendpoint = api.endpoint_template.endpoint_add(dendpoint)
- dendpoint = endpoints.Endpoint(dendpoint.id, url + \
- '/endpointTemplates/' + \
- dendpoint.endpoint_template_id)
+ dendpoint = Endpoint(dendpoint.id, url +
+ '/endpointTemplates/' + dendpoint.endpoint_template_id)
return dendpoint
def delete_endpoint(self, admin_token, endpoint_id):
diff --git a/keystone/logic/types/atom.py b/keystone/logic/types/atom.py
index 0b2345d9..3db1166c 100644
--- a/keystone/logic/types/atom.py
+++ b/keystone/logic/types/atom.py
@@ -16,7 +16,7 @@ from lxml import etree
class Link(object):
- "An atom link"
+ """An atom link"""
def __init__(self, rel, href, link_type=None, hreflang=None, title=None):
self.rel = rel
diff --git a/keystone/logic/types/auth.py b/keystone/logic/types/auth.py
index fe2d7a0c..be13019b 100755
--- a/keystone/logic/types/auth.py
+++ b/keystone/logic/types/auth.py
@@ -13,14 +13,10 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-from abc import ABCMeta
-from datetime import datetime
import json
from lxml import etree
-import keystone.logic.types.fault as fault
-import keystone.logic.types.role as roles
-
+from keystone.logic.types import fault
class PasswordCredentials(object):
"""Credentials based on username, password, and (optional) tenant_id.
@@ -83,7 +79,7 @@ class PasswordCredentials(object):
class Token(object):
- "An auth token."
+ """An auth token."""
def __init__(self, expires, token_id, tenant_id=None):
self.expires = expires
@@ -92,7 +88,7 @@ class Token(object):
class Group(object):
- "A group, optionally belonging to a tenant."
+ """A group, optionally belonging to a tenant."""
def __init__(self, group_id, tenant_id):
self.tenant_id = tenant_id
@@ -100,7 +96,7 @@ class Group(object):
class Groups(object):
- "A collection of groups."
+ """A collection of groups."""
def __init__(self, values, links):
self.values = values
@@ -108,7 +104,7 @@ class Groups(object):
class User(object):
- "A user."
+ """A user."""
def __init__(self, username, tenant_id, groups, role_refs=None):
self.username = username
@@ -118,7 +114,7 @@ class User(object):
class AuthData(object):
- "Authentation Information returned upon successful login."
+ """Authentation Information returned upon successful login."""
def __init__(self, token, base_urls=None):
self.token = token
@@ -145,15 +141,15 @@ class AuthData(object):
endpoint.set("region", base_url.region)
if base_url.public_url:
endpoint.set("publicURL",
- base_url.public_url.replace('%tenant_id%',\
+ base_url.public_url.replace('%tenant_id%', \
self.token.tenant_id))
if base_url.admin_url:
endpoint.set("adminURL",
- base_url.admin_url.replace('%tenant_id%',\
+ base_url.admin_url.replace('%tenant_id%', \
self.token.tenant_id))
if base_url.internal_url:
endpoint.set("internalURL",
- base_url.internal_url.replace('%tenant_id%',\
+ base_url.internal_url.replace('%tenant_id%', \
self.token.tenant_id))
service.append(endpoint)
service_catalog.append(service)
@@ -181,10 +177,10 @@ class AuthData(object):
if base_url.region:
endpoint["region"] = base_url.region
if base_url.public_url:
- endpoint["publicURL"] = base_url.public_url.replace( \
+ endpoint["publicURL"] = base_url.public_url.replace(\
'%tenant_id%', self.token.tenant_id)
if base_url.admin_url:
- endpoint["adminURL"] = base_url.admin_url.replace( \
+ endpoint["adminURL"] = base_url.admin_url.replace(\
'%tenant_id%', self.token.tenant_id)
if base_url.internal_url:
endpoint["internalURL"] = base_url.internal_url.\
@@ -198,7 +194,7 @@ class AuthData(object):
class ValidateData(object):
- "Authentation Information returned upon successful token validation."
+ """Authentation Information returned upon successful token validation."""
def __init__(self, token, user):
self.token = token
diff --git a/keystone/logic/types/endpoint.py b/keystone/logic/types/endpoint.py
index bd575285..71f14fa2 100644
--- a/keystone/logic/types/endpoint.py
+++ b/keystone/logic/types/endpoint.py
@@ -15,12 +15,13 @@
import json
from lxml import etree
-import string
-import keystone.logic.types.fault as fault
+from keystone.logic.types import fault
class EndpointTemplate(object):
+ """Document me!"""
+
@staticmethod
def from_xml(xml_str):
try:
@@ -156,7 +157,7 @@ class EndpointTemplate(object):
class EndpointTemplates(object):
- "A collection of endpointTemplates."
+ """A collection of endpointTemplates."""
def __init__(self, values, links):
self.values = values
@@ -182,6 +183,8 @@ class EndpointTemplates(object):
class Endpoint(object):
+ """Document me!"""
+
def __init__(self, id, href):
self.id = id
self.href = href
@@ -211,7 +214,7 @@ class Endpoint(object):
class Endpoints(object):
- "A collection of endpoints."
+ """A collection of endpoints."""
def __init__(self, values, links):
self.values = values
diff --git a/keystone/logic/types/fault.py b/keystone/logic/types/fault.py
index fa69dd13..8382d82e 100644
--- a/keystone/logic/types/fault.py
+++ b/keystone/logic/types/fault.py
@@ -18,7 +18,7 @@ from lxml import etree
class IdentityFault(Exception):
- "Base Exception type for all auth exceptions"
+ """Base Exception type for all auth exceptions"""
def __init__(self, msg, details=None, code=500):
self.args = (code, msg, details)
@@ -56,7 +56,7 @@ class IdentityFault(Exception):
class ServiceUnavailableFault(IdentityFault):
- "The auth service is unavailable"
+ """The auth service is unavailable"""
def __init__(self, msg, details=None, code=503):
super(ServiceUnavailableFault, self).__init__(msg, details, code)
@@ -64,7 +64,7 @@ class ServiceUnavailableFault(IdentityFault):
class BadRequestFault(IdentityFault):
- "Bad user request"
+ """Bad user request"""
def __init__(self, msg, details=None, code=400):
super(BadRequestFault, self).__init__(msg, details, code)
@@ -72,7 +72,7 @@ class BadRequestFault(IdentityFault):
class UnauthorizedFault(IdentityFault):
- "User is unauthorized"
+ """User is unauthorized"""
def __init__(self, msg, details=None, code=401):
super(UnauthorizedFault, self).__init__(msg, details, code)
@@ -80,7 +80,7 @@ class UnauthorizedFault(IdentityFault):
class ForbiddenFault(IdentityFault):
- "The user is forbidden"
+ """The user is forbidden"""
def __init__(self, msg, details=None, code=403):
super(ForbiddenFault, self).__init__(msg, details, code)
@@ -88,7 +88,7 @@ class ForbiddenFault(IdentityFault):
class ItemNotFoundFault(IdentityFault):
- "The item is not found"
+ """The item is not found"""
def __init__(self, msg, details=None, code=404):
super(ItemNotFoundFault, self).__init__(msg, details, code)
@@ -96,7 +96,7 @@ class ItemNotFoundFault(IdentityFault):
class TenantDisabledFault(IdentityFault):
- "The tenant is disabled"
+ """The tenant is disabled"""
def __init__(self, msg, details=None, code=403):
super(TenantDisabledFault, self).__init__(msg, details, code)
@@ -104,7 +104,7 @@ class TenantDisabledFault(IdentityFault):
class TenantConflictFault(IdentityFault):
- "The tenant already exists?"
+ """The tenant already exists?"""
def __init__(self, msg, details=None, code=409):
super(TenantConflictFault, self).__init__(msg, details, code)
@@ -112,7 +112,7 @@ class TenantConflictFault(IdentityFault):
class TenantGroupConflictFault(IdentityFault):
- "The tenant Group already exists?"
+ """The tenant Group already exists?"""
def __init__(self, msg, details=None, code=409):
super(TenantGroupConflictFault, self).__init__(msg, details, code)
@@ -120,7 +120,7 @@ class TenantGroupConflictFault(IdentityFault):
class OverlimitFault(IdentityFault):
- "A limit has been exceeded"
+ """A limit has been exceeded"""
def __init__(self, msg, details=None, code=409, retry_at=None):
super(OverlimitFault, self).__init__(msg, details, code)
@@ -130,7 +130,7 @@ class OverlimitFault(IdentityFault):
class UserConflictFault(IdentityFault):
- "The User already exists?"
+ """The User already exists?"""
def __init__(self, msg, details=None, code=409):
super(UserConflictFault, self).__init__(msg, details, code)
@@ -138,7 +138,7 @@ class UserConflictFault(IdentityFault):
class UserDisabledFault(IdentityFault):
- "The user is disabled"
+ """The user is disabled"""
def __init__(self, msg, details=None, code=403):
super(UserDisabledFault, self).__init__(msg, details, code)
@@ -146,7 +146,7 @@ class UserDisabledFault(IdentityFault):
class EmailConflictFault(IdentityFault):
- "The Email already exists?"
+ """The Email already exists?"""
def __init__(self, msg, details=None, code=409):
super(EmailConflictFault, self).__init__(msg, details, code)
@@ -154,7 +154,7 @@ class EmailConflictFault(IdentityFault):
class UserGroupConflictFault(IdentityFault):
- "The user already exists in group?"
+ """The user already exists in group?"""
def __init__(self, msg, details=None, code=409):
super(UserGroupConflictFault, self).__init__(msg, details, code)
@@ -162,7 +162,7 @@ class UserGroupConflictFault(IdentityFault):
class RoleConflictFault(IdentityFault):
- "The User already exists?"
+ """The User already exists?"""
def __init__(self, msg, details=None, code=409):
super(RoleConflictFault, self).__init__(msg, details, code)
diff --git a/keystone/logic/types/role.py b/keystone/logic/types/role.py
index fd530ab0..f609e0ac 100644
--- a/keystone/logic/types/role.py
+++ b/keystone/logic/types/role.py
@@ -17,7 +17,7 @@ import json
from lxml import etree
import string
-import keystone.logic.types.fault as fault
+from keystone.logic.types import fault
class Role(object):
diff --git a/keystone/logic/types/tenant.py b/keystone/logic/types/tenant.py
index 652e3741..cdf88e0e 100644
--- a/keystone/logic/types/tenant.py
+++ b/keystone/logic/types/tenant.py
@@ -17,16 +17,16 @@ import json
from lxml import etree
import string
-import keystone.logic.types.fault as fault
+from keystone.logic.types import fault
class Tenant(object):
- "Describes a tenant in the auth system"
+ """Describes a tenant in the auth system"""
def __init__(self, tenant_id, description, enabled):
self.tenant_id = tenant_id
self.description = description
- self.enabled = enabled and True or False
+ self.enabled = enabled
@staticmethod
def from_xml(xml_str):
@@ -103,7 +103,7 @@ class Tenant(object):
class Tenants(object):
- "A collection of tenants."
+ """A collection of tenants."""
def __init__(self, values, links):
self.values = values
@@ -128,7 +128,7 @@ class Tenants(object):
class Group(object):
- "Describes a group in the auth system"
+ """Describes a group in the auth system"""
def __init__(self, group_id, description, tenant_id):
self.description = description
@@ -143,7 +143,7 @@ class Group(object):
try:
dom = etree.Element("root")
dom.append(etree.fromstring(xml_str))
- root = dom.find( \
+ root = dom.find(\
"{http://docs.openstack.org/identity/api/v2.0}group")
if root == None:
raise fault.BadRequestFault("Expecting Group")
@@ -217,7 +217,7 @@ class Group(object):
class Groups(object):
- "A collection of groups."
+ """A collection of groups."""
def __init__(self, values, links):
self.values = values
@@ -242,7 +242,7 @@ class Groups(object):
class GlobalGroup(object):
- "Describes a group in the auth system"
+ """Describes a group in the auth system"""
def __init__(self, group_id, description, tenant_id=None):
self.description = description
@@ -315,7 +315,7 @@ class GlobalGroup(object):
class GlobalGroups(object):
- "A collection of groups."
+ """A collection of groups."""
def __init__(self, values, links):
self.values = values
@@ -340,7 +340,11 @@ class GlobalGroups(object):
class User(object):
- "Describes a user in the auth system"
+ """Describes a user in the auth system
+
+ TODO: This is basically a duplicate of keystone.logic.types.user.User and
+ should be considered deprecated.
+ """
def __init__(self, user_id, email, enabled, tenant_id='', group_id=''):
self.user_id = user_id
@@ -386,28 +390,3 @@ class User(object):
def to_json(self):
return json.dumps(self.to_dict())
-
-
-class Users(object):
- "A collection of users."
-
- def __init__(self, values, links):
- self.values = values
- self.links = links
-
- def to_xml(self):
- dom = etree.Element("users")
- dom.set(u"xmlns", "http://docs.openstack.org/identity/api/v2.0")
-
- for t in self.values:
- dom.append(t.to_dom())
-
- for t in self.links:
- dom.append(t.to_dom())
-
- return etree.tostring(dom)
-
- def to_json(self):
- values = [t.to_dict()["user"] for t in self.values]
- links = [t.to_dict()["links"] for t in self.links]
- return json.dumps({"users": {"values": values, "links": links}})
diff --git a/keystone/logic/types/user.py b/keystone/logic/types/user.py
index 795eb21e..f1b89a1f 100755
--- a/keystone/logic/types/user.py
+++ b/keystone/logic/types/user.py
@@ -17,10 +17,11 @@ import json
from lxml import etree
import string
-import keystone.logic.types.fault as fault
+from keystone.logic.types import fault
class User(object):
+ """Document me!"""
def __init__(self, password, user_id, tenant_id, email, enabled):
self.user_id = user_id
@@ -128,7 +129,8 @@ class User(object):
class User_Update(object):
-
+ """Document me!"""
+
def __init__(self, password, user_id, tenant_id, email,
enabled, group=None):
self.user_id = user_id
@@ -244,7 +246,7 @@ class User_Update(object):
class Users(object):
- "A collection of users."
+ """A collection of users."""
def __init__(self, values, links):
self.values = values
diff --git a/keystone/middleware/url.py b/keystone/middleware/url.py
index 3c876b8c..fdbcf794 100644
--- a/keystone/middleware/url.py
+++ b/keystone/middleware/url.py
@@ -69,7 +69,7 @@ class UrlRewriteFilter(object):
def remove_trailing_slash(self, path_info):
"""Removes a trailing slash from the given path, if any"""
- if path_info[-1] == '/':
+ if len(path_info) > 1 and path_info[-1] == '/':
return path_info[:-1]
else:
return path_info
diff --git a/keystone/routers/public.py b/keystone/routers/service.py
index b224a811..6039274d 100644
--- a/keystone/routers/public.py
+++ b/keystone/routers/service.py
@@ -7,8 +7,8 @@ from keystone.controllers.tenant import TenantController
from keystone.controllers.version import VersionController
from keystone.controllers.staticfiles import StaticFilesController
-class PublicApi(wsgi.Router):
- """WSGI entry point for public Keystone API requests."""
+class ServiceApi(wsgi.Router):
+ """WSGI entry point for Keystone Service API requests."""
def __init__(self, options):
self.options = options
@@ -52,4 +52,4 @@ class PublicApi(wsgi.Router):
action="get_pdf_contract",
conditions=dict(method=["GET"]))
- super(PublicApi, self).__init__(mapper)
+ super(ServiceApi, self).__init__(mapper)
diff --git a/keystone/server.py b/keystone/server.py
index 48895b68..74240d6e 100755
--- a/keystone/server.py
+++ b/keystone/server.py
@@ -35,24 +35,17 @@ HTTP_AUTHORIZATION : basic auth password used to validate the connection
HTTP_X_AUTHORIZATION: the client identity being passed in
"""
-from keystone.backends import alterdb, sqlalchemy #@UnusedImport (?)
-from keystone.routers.public import PublicApi
+from keystone.routers.service import ServiceApi
from keystone.routers.admin import AdminApi
-def app_factory(global_conf, **local_conf):
+def service_app_factory(global_conf, **local_conf):
"""paste.deploy app factory for creating OpenStack API server apps"""
- try:
- conf = global_conf.copy()
- conf.update(local_conf)
- except Exception as err:
- print err
- return PublicApi(conf)
+ conf = global_conf.copy()
+ conf.update(local_conf)
+ return ServiceApi(conf)
def admin_app_factory(global_conf, **local_conf):
"""paste.deploy app factory for creating OpenStack API server apps"""
- try:
- conf = global_conf.copy()
- conf.update(local_conf)
- except Exception as err:
- print err
+ conf = global_conf.copy()
+ conf.update(local_conf)
return AdminApi(conf)
diff --git a/keystone/test/run_tests.py b/keystone/test/run_tests.py
index 15fb8ede..c7a5df18 100644
--- a/keystone/test/run_tests.py
+++ b/keystone/test/run_tests.py
@@ -25,9 +25,13 @@ if __name__ == '__main__':
sys.exit(-1)
try:
- # run tests
- subprocess.check_call(['python',
- os.path.join(test_dir, 'unit/test_keystone.py')])
+ # run unit tests
+ subprocess.check_call(
+ ['python', os.path.join(test_dir, 'unit/test_keystone.py')])
+
+ # run system tests
+ subprocess.check_call(
+ ['unit2', 'discover', 'keystone.test.system'])
finally:
#kill the keystone server
server.kill()
diff --git a/keystone/test/system/__init__.py b/keystone/test/system/__init__.py
new file mode 100644
index 00000000..8b137891
--- /dev/null
+++ b/keystone/test/system/__init__.py
@@ -0,0 +1 @@
+
diff --git a/keystone/test/system/common.py b/keystone/test/system/common.py
new file mode 100644
index 00000000..71d42646
--- /dev/null
+++ b/keystone/test/system/common.py
@@ -0,0 +1,98 @@
+import unittest
+import httplib
+
+class RestfulTestCase(unittest.TestCase):
+ """Performs generic HTTP request testing"""
+
+ def setUp(self):
+ """Sets default connection settings"""
+ self.host = '127.0.0.1'
+ self.port = 80
+
+ def request(self, method='GET', path='/', headers={}, body=None,
+ expect_exception=False):
+ """Perform request and fetch httplib.HTTPResponse from the server
+
+ Dynamically includes 'json' and 'xml' attributes based on the detected
+ response type, and fails the current test case if unsuccessful.
+
+ response.json: standard python dictionary
+ response.xml: xml.etree.ElementTree
+ """
+
+ # Initialize a connection
+ connection = httplib.HTTPConnection(self.host, self.port, timeout=3)
+
+ # Perform the request
+ connection.request(method, path, body, headers)
+
+ # Retrieve the response so can go ahead and close the connection
+ response = connection.getresponse()
+ response.body = response.read()
+
+ # Close the connection
+ connection.close()
+
+ # Automatically assert HTTP status code
+ if not expect_exception:
+ self.assertSuccessfulResponse(response.status)
+ else:
+ self.assertExceptionalResponse(response.status)
+
+ # Attempt to parse JSON and XML automatically, if detected
+ response = self._parseResponseBody(response)
+
+ # This contains the response headers, body, parsed json/xml, etc
+ return response
+
+ def assertSuccessfulResponse(self, status_code):
+ """Asserts that a status code lies in the 2xx range"""
+ self.assertTrue(status_code >= 200 and status_code <= 299)
+
+ def assertExceptionalResponse(self, status_code):
+ """Asserts that a status code lies outside the 2xx range"""
+ self.assertTrue(status_code < 200 or status_code > 299)
+
+ def _parseResponseBody(self, response):
+ """Detects response body type, and attempts to decode it"""
+ if 'application/json' in response.getheader('Content-Type'):
+ response.json = self._parseJson(response.body)
+ elif 'application/xml' in response.getheader('Content-Type'):
+ response.xml = self._parseXml(response.body)
+ return response
+
+ def _parseXml(self, xml_str):
+ """Returns an ElementTree of the given XML string"""
+ try:
+ import xml.etree.ElementTree
+ return xml.etree.ElementTree.fromstring(xml_str)
+ except Exception as e:
+ self.fail(e)
+
+ def _parseJson(self, json_str):
+ """Returns a dict of the given JSON string"""
+ try:
+ import json
+ return json.loads(json_str)
+ except Exception as e:
+ self.fail(e)
+
+class ServiceTestCase(RestfulTestCase):
+ """Perform generic HTTP request testing against Service API"""
+
+ def setUp(self):
+ """Sets custom connection settings"""
+ super(ServiceTestCase, self).setUp()
+
+ # Override parent's connection settings
+ self.port = 5000 # The port the service API is expected to run on
+
+class AdminTestCase(RestfulTestCase):
+ """Perform generic HTTP request testing against Admin API"""
+
+ def setUp(self):
+ """Sets custom connection settings"""
+ super(AdminTestCase, self).setUp()
+
+ # Override parent's connection settings
+ self.port = 5001 # The port the admin API is expected to run on
diff --git a/keystone/test/system/test_request_specs.py b/keystone/test/system/test_request_specs.py
new file mode 100644
index 00000000..66c005ba
--- /dev/null
+++ b/keystone/test/system/test_request_specs.py
@@ -0,0 +1,58 @@
+import unittest
+from common import AdminTestCase
+
+class TestUrlHandling(AdminTestCase):
+ """Tests API's global URL handling behaviors"""
+
+ def test_optional_trailing_slash(self):
+ """Same response returned regardless of a trailing slash in the url."""
+ r1 = self.request(path='/v2.0/')
+ r2 = self.request(path='/v2.0')
+ self.assertEqual(r1.read(), r2.read())
+
+class TestContentTypes(AdminTestCase):
+ """Tests API's Content-Type handling"""
+
+ def test_default_content_type(self):
+ """Service returns JSON without being asked to"""
+ r = self.request(path='/v2.0')
+ self.assertTrue('application/json' in r.getheader('Content-Type'))
+
+ def test_xml_extension(self):
+ """Service responds to .xml URL extension"""
+ r = self.request(path='/v2.0.xml')
+ self.assertTrue('application/xml' in r.getheader('Content-Type'))
+
+ def test_json_extension(self):
+ """Service responds to .json URL extension"""
+ r = self.request(path='/v2.0.json')
+ self.assertTrue('application/json' in r.getheader('Content-Type'))
+
+ def test_xml_accept_header(self):
+ """Service responds to xml Accept header"""
+ r = self.request(path='/v2.0',
+ headers={'Accept': 'application/xml'})
+ self.assertTrue('application/xml' in r.getheader('Content-Type'))
+
+ def test_json_accept_header(self):
+ """Service responds to json Accept header"""
+ r = self.request(path='/v2.0',
+ headers={'Accept': 'application/json'})
+ self.assertTrue('application/json' in r.getheader('Content-Type'))
+
+ def test_xml_extension_overrides_conflicting_header(self):
+ """Service returns XML when Accept header conflicts with extension"""
+ r = self.request(path='/v2.0.xml',
+ headers={'Accept': 'application/json'})
+
+ self.assertTrue('application/xml' in r.getheader('Content-Type'))
+
+ def test_json_extension_overrides_conflicting_header(self):
+ """Service returns JSON when Accept header conflicts with extension"""
+ r = self.request(path='/v2.0.json',
+ headers={'Accept': 'application/xml'})
+
+ self.assertTrue('application/json' in r.getheader('Content-Type'))
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/keystone/test/unit/base.py b/keystone/test/unit/base.py
index c2dff063..bfa56a61 100644
--- a/keystone/test/unit/base.py
+++ b/keystone/test/unit/base.py
@@ -28,7 +28,7 @@ import webob
from keystone import server
import keystone.backends.sqlalchemy as db
-import keystone.backends.sqlalchemy.api as db_api
+import keystone.backends.api as db_api
logger = logging.getLogger('test.unit.base')
@@ -43,7 +43,7 @@ class ServiceAPITest(unittest.TestCase):
The `api` attribute for this base class is the `server.KeystoneAPI`
controller.
"""
- api_class = server.KeystoneAPI
+ api_class = server.ServiceApi
"""
Dict of configuration options to pass to the API controller
@@ -257,7 +257,7 @@ class AdminAPITest(ServiceAPITest):
The `api` attribute for this base class is the `server.KeystoneAdminAPI`
controller.
"""
- api_class = server.KeystoneAdminAPI
+ api_class = server.AdminApi
"""
Set of dicts of tenant attributes we start each test case with
diff --git a/keystone/test/unit/test_authentication.py b/keystone/test/unit/test_authentication.py
index b91ff75d..9cb18e80 100755
--- a/keystone/test/unit/test_authentication.py
+++ b/keystone/test/unit/test_authentication.py
@@ -18,37 +18,24 @@
import httplib2
import json
from lxml import etree
-import os
-import sys
-# Need to access identity module
-sys.path.append(os.path.abspath(os.path.join(os.path.abspath(__file__),
- '..', '..', '..', '..', '..', 'keystone')))
import unittest
import test_common as utils
-from keystone.logic.types import fault
+from keystone.logic.types import fault
class AuthenticationTest(unittest.TestCase):
def setUp(self):
-
self.tenant = utils.get_tenant()
- self.token = utils.get_token('joeuser', 'secrete', self.tenant,
- 'token')
- #self.user = utils.get_user()
+ self.token = utils.get_token(
+ 'joeuser', 'secrete', self.tenant, 'token')
self.userdisabled = utils.get_userdisabled()
self.auth_token = utils.get_auth_token()
utils.delete_all_endpoint(self.tenant, self.auth_token)
- utils.create_endpoint(self.tenant, "1",
- str(self.auth_token))
- utils.create_endpoint(self.tenant, "2",
- str(self.auth_token))
- utils.create_endpoint(self.tenant, "3",
- str(self.auth_token))
- utils.create_endpoint(self.tenant, "4",
- str(self.auth_token))
- #self.exp_auth_token = utils.get_exp_auth_token()
- #self.disabled_token = utils.get_disabled_token()
+ utils.create_endpoint(self.tenant, "1", str(self.auth_token))
+ utils.create_endpoint(self.tenant, "2", str(self.auth_token))
+ utils.create_endpoint(self.tenant, "3", str(self.auth_token))
+ utils.create_endpoint(self.tenant, "4", str(self.auth_token))
def tearDown(self):
utils.delete_token(self.token, self.auth_token)
@@ -84,11 +71,11 @@ class AuthenticationTest(unittest.TestCase):
self.fail("Expecting Service Catalog")
def test_a_authorize_legacy(self):
- resp, content = utils.get_token_legacy('joeuser', 'secrete')
+ resp, _content = utils.get_token_legacy('joeuser', 'secrete')
self.assertEqual(204, int(resp['status']))
self.assertTrue(resp['x-auth-token'])
- #self.assertTrue(resp['x-server-management-url'])
- #self.assertTrue(resp['x-storage-url'])
+ self.assertTrue(resp['x-server-management-url'])
+ self.assertTrue(resp['x-storage-url'])
self.assertTrue(resp['x-glance'])
#Assert Existence of global endpoint
self.assertTrue(resp['x-identity'])
@@ -171,19 +158,11 @@ class MultiToken(unittest.TestCase):
def setUp(self):
self.auth_token = utils.get_auth_token()
self.userdisabled = utils.get_userdisabled()
- resp1, content1 = utils.create_tenant('test_tenant1', self.auth_token)
- #create tenant2
- resp2, content2 = utils.create_tenant('test_tenant2', self.auth_token)
- #create user1 with tenant1
- resp3, content3 = utils.create_user('test_tenant1', 'test_user1',
- self.auth_token)
- resp3, content3 = utils.create_user('test_tenant1', 'test_user2',
- self.auth_token)
- #add user1 to tenant2
- resp4, content4 = utils.add_user_json('test_tenant2', 'test_user1',
- self.auth_token)
- #self.exp_auth_token = utils.get_exp_auth_token()
- #self.disabled_token = utils.get_disabled_token()
+ utils.create_tenant('test_tenant1', self.auth_token)
+ utils.create_tenant('test_tenant2', self.auth_token)
+ utils.create_user('test_tenant1', 'test_user1', self.auth_token)
+ utils.create_user('test_tenant1', 'test_user2', self.auth_token)
+ utils.add_user_json('test_tenant2', 'test_user1', self.auth_token)
def tearDown(self):
utils.delete_user('test_user1', self.auth_token)
@@ -192,26 +171,9 @@ class MultiToken(unittest.TestCase):
utils.delete_tenant('test_tenant1', self.auth_token)
utils.delete_tenant('test_tenant2', self.auth_token)
- """ INVALID TEST - we're changing how we delegate access to second tenant
- def test_multi_token(self):
- #get token for user1 with tenant1
- token1 = utils.get_token('test_user1', 'secrete', 'test_tenant1',\
- 'token')
- #get token for user 1 with tenant2
- token2 = utils.get_token('test_user1', 'secrete', 'test_tenant2',\
- 'token')
- #test result :: both token should be different
- self.assertNotEqual(token1, None)
- self.assertNotEqual(token2, None)
- self.assertNotEqual(token1, token2)
-
- resp = utils.delete_token(token1, self.auth_token)
- resp = utils.delete_token(token2, self.auth_token)
- """
-
def test_unassigned_user(self):
- resp, content = utils.get_token('test_user2', 'secrete', \
- 'test_tenant')
+ resp, _content = utils.get_token(
+ 'test_user2', 'secrete', 'test_tenant')
self.assertEqual(401, int(resp['status']))
diff --git a/keystone/test/unit/test_groups.py b/keystone/test/unit/test_groups.py
index c9c2ebd9..bb1c63ec 100755
--- a/keystone/test/unit/test_groups.py
+++ b/keystone/test/unit/test_groups.py
@@ -23,7 +23,6 @@ import sys
sys.path.append(os.path.abspath(os.path.join(os.path.abspath(__file__),
'..', '..', '..', '..', '..', 'keystone')))
import unittest
-from webtest import TestApp
import test_common as utils
@@ -749,7 +748,7 @@ class GetUsersTenantGroupTest(unittest.TestCase):
utils.create_user(self.tenant, self.user, str(self.auth_token))
utils.add_user_global_group(self.global_group, self.user,
str(self.auth_token))
- resp_new, content_new = utils.get_user_global_group(\
+ resp_new, content_new = utils.get_user_global_group(
self.global_group,
str(self.auth_token))
diff --git a/keystone/test/unit/test_urlrewritefilter.py b/keystone/test/unit/test_urlrewritefilter.py
index e22c362f..14c13792 100644
--- a/keystone/test/unit/test_urlrewritefilter.py
+++ b/keystone/test/unit/test_urlrewritefilter.py
@@ -43,9 +43,10 @@ class UrlExtensionFilterTest(unittest.TestCase):
self.assertEqual('/v2.0', env['PATH_INFO'])
def test_remove_trailing_slash_from_empty_path(self):
+ """Empty paths should still equate to a slash"""
env = {'PATH_INFO': '/'}
self.filter(env, _start_response)
- self.assertEqual('', env['PATH_INFO'])
+ self.assertEqual('/', env['PATH_INFO'])
def test_no_extension(self):
env = {'PATH_INFO': '/v2.0/someresource'}
diff --git a/keystone/utils.py b/keystone/utils.py
index 96991364..321381ff 100755
--- a/keystone/utils.py
+++ b/keystone/utils.py
@@ -15,17 +15,12 @@
# limitations under the License.
-import functools
-import logging
import os
import sys
-from webob import Response
+import logging
+import functools
-POSSIBLE_TOPDIR = os.path.normpath(os.path.join(os.path.abspath(sys.argv[0]),
- os.pardir,
- os.pardir))
-if os.path.exists(os.path.join(POSSIBLE_TOPDIR, 'keystone', '__init__.py')):
- sys.path.insert(0, POSSIBLE_TOPDIR)
+from webob import Response
import keystone.logic.types.fault as fault
@@ -40,24 +35,18 @@ def get_app_root():
def get_auth_token(req):
- auth_token = None
if "X-Auth-Token" in req.headers:
- auth_token = req.headers["X-Auth-Token"]
- return auth_token
+ return req.headers["X-Auth-Token"]
def get_auth_user(req):
- auth_user = None
if "X-Auth-User" in req.headers:
- auth_user = req.headers["X-Auth-User"]
- return auth_user
+ return req.headers["X-Auth-User"]
def get_auth_key(req):
- auth_key = None
if "X-Auth-Key" in req.headers:
- auth_key = req.headers["X-Auth-Key"]
- return auth_key
+ return req.headers["X-Auth-Key"]
def wrap_error(func):
@@ -80,31 +69,27 @@ def wrap_error(func):
def get_normalized_request_content(model, req):
"""Initialize a model from json/xml contents of request body"""
- if req.content_type == "application/xml":
- ret = model.from_xml(req.body)
+ if req.content_type == "application/xml":
+ return model.from_xml(req.body)
elif req.content_type == "application/json":
- ret = model.from_json(req.body)
+ return model.from_json(req.body)
else:
- raise fault.IdentityFault("I don't understand the content type ",
+ raise fault.IdentityFault("I don't understand the content type",
code=415)
- return ret
def send_error(code, req, result):
content = None
- resp = Response()
+ resp = Response()
resp.headers['content-type'] = None
resp.status = code
if result:
-
if is_xml_response(req):
-
content = result.to_xml()
resp.headers['content-type'] = "application/xml"
else:
-
content = result.to_json()
resp.headers['content-type'] = "application/json"
@@ -116,6 +101,7 @@ def send_error(code, req, result):
def send_result(code, req, result):
content = None
+
resp = Response()
resp.headers['content-type'] = None
resp.status = code
@@ -123,7 +109,6 @@ def send_result(code, req, result):
return resp
if result:
-
if is_xml_response(req):
content = result.to_xml()
resp.headers['content-type'] = "application/xml"
@@ -151,10 +136,12 @@ def send_legacy_result(code, headers):
return resp
-#Currently using sha1 to hash.Need to figure if there is an openstack standard.Not using salt val as of now.
+# Currently using sha1 to hash, without a salt value.
+# Need to research relevant openstack standards.
def get_hashed_password(password):
if password != None and len(password) > 0:
return password
+ # why is this disabled?
#return hashlib.sha1(password).hexdigest()
else:
return None