diff options
| author | Ziad Sawalha <ziad.sawalha@rackspace.com> | 2011-07-13 14:03:12 -0700 |
|---|---|---|
| committer | Ziad Sawalha <ziad.sawalha@rackspace.com> | 2011-07-13 14:03:12 -0700 |
| commit | 3873d2a409882b5f9dddfe96aa26fe1f3645a54f (patch) | |
| tree | 1465850cc68ba1b9045343f790bba2ea5097660b | |
| parent | d59fc3a22cfdc50715a3831b6bff202bfc079169 (diff) | |
| parent | 0d8f222173ad23808561ff66d762f36aa04b92f1 (diff) | |
Merge pull request #95 from dolph/master
Added system test discovery to run_tests.py
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 |
