From ebeda76d08632b3a43d387e8c489dfffb65009ee Mon Sep 17 00:00:00 2001 From: Adipudi Praveena Date: Tue, 10 May 2011 20:20:16 +0530 Subject: Added the keystone top dir in configuration --- bin/keystone-auth | 2 +- etc/keystone.conf | 6 +- keystone/auth_server.py | 639 ---------------------------------- keystone/common/config.py | 39 ++- keystone/server.py | 849 +++++++++++++++++++++++++++++---------------- setup.py | 18 +- test/unit/test_identity.py | 2 +- 7 files changed, 583 insertions(+), 972 deletions(-) delete mode 100755 keystone/auth_server.py mode change 100644 => 100755 keystone/server.py diff --git a/bin/keystone-auth b/bin/keystone-auth index c1e75daf..eae99ec9 100755 --- a/bin/keystone-auth +++ b/bin/keystone-auth @@ -57,7 +57,7 @@ if __name__ == '__main__': (options, args) = config.parse_options(oparser) try: - conf, app = config.load_paste_app('auth_server', options, args) + conf, app = config.load_paste_app('server', options, args) server = wsgi.Server() server.start(app, int(conf['bind_port']), conf['bind_host']) server.wait() diff --git a/etc/keystone.conf b/etc/keystone.conf index c85fd25a..3b2d4457 100644 --- a/etc/keystone.conf +++ b/etc/keystone.conf @@ -5,10 +5,10 @@ verbose = True # Show debugging output in logs (sets DEBUG log level output) debug = False -[app:auth_server] -paste.app_factory = keystone.auth_server:app_factory +[app:server] +paste.app_factory = keystone.server:app_factory -# Which backend store should Glance use by default is not specified +# Which backend store should Keystone use by default is not specified # in a request to add a new image to Glance? Default: 'file' # Available choices are 'file', 'swift', and 's3' default_store = file diff --git a/keystone/auth_server.py b/keystone/auth_server.py deleted file mode 100755 index 6203dde4..00000000 --- a/keystone/auth_server.py +++ /dev/null @@ -1,639 +0,0 @@ -# vim: tabstop=4 shiftwidth=4 softtabstop=4 -# Copyright (c) 2010-2011 OpenStack, LLC. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -# implied. -# See the License for the specific language governing permissions and -# limitations under the License. - - -""" -Service that stores identities and issues and manages tokens - -HEADERS -------- -HTTP_ is a standard http header -HTTP_X is an extended http header - -> Coming in from initial call -HTTP_X_AUTH_TOKEN : the client token being passed in -HTTP_X_STORAGE_TOKEN: the client token being passed in (legacy Rackspace use) - to support cloud files -> Used for communication between components -www-authenticate : only used if this component is being used remotely -HTTP_AUTHORIZATION : basic auth password used to validate the connection - -> What we add to the request for use by the OpenStack service -HTTP_X_AUTHORIZATION: the client identity being passed in - -""" -import functools -import logging -import os -import sys -import httplib -import json - -import routes -from webob import Response -from webob import Request -from webob import descriptors -from webob.exc import (HTTPNotFound, - HTTPConflict, - HTTPBadRequest) - -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 queryext import exthandler -from keystone.common import wsgi -import keystone.logic.service as serv -import keystone.logic.types.tenant as tenants -import keystone.logic.types.auth as auth -import keystone.logic.types.fault as fault -import keystone.logic.types.user as users -import keystone.common.template as template - - -VERSION_STATUS = "ALPHA" -VERSION_DATE = "2011-04-23T00:00:00Z" - -service = serv.IDMService() - - -def is_xml_response(req): - if not "Accept" in req.headers: - return False - return req.content_type == "application/xml" - - -def get_app_root(): - return os.path.abspath(os.path.dirname(__file__)) - - -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 - - -def wrap_error(func): - @functools.wraps(func) - def check_error(*args, **kwargs): - print '>>>>>>>>>>>>>>>>>>..' - try: - - return func(*args, **kwargs) - - except Exception as err: - if isinstance(err, fault.IDMFault): - return send_error(err.code, kwargs['req'], err) - else: - logging.exception(err) - return send_error(500, kwargs['req'], fault.IDMFault("Unhandled error", str(err))) - return check_error - - -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) - elif req.content_type == "application/json": - - ret = model.from_json(req.body) - else: - - raise fault.IDMFault("I don't understand the content type ", code=415) - return ret - -def send_error(code, req, result): - content = None - 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" - - resp.content_type_params={'charset' : 'UTF-8'} - resp.unicode_body = content.decode('UTF-8') - - return resp - - -def send_result(code, req, result): - content = None - resp = Response() - resp.headers['content-type'] = None - resp.status = code - if code > 399: - return resp - - 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" - - resp.content_type_params={'charset' : 'UTF-8'} - resp.unicode_body = content.decode('UTF-8') - - return resp - -class StaticFilesController(wsgi.Controller): - - def __init__(self, options): - self.options = options - - @wrap_error - def get_pdf_contract(self, req): - resp = Response() - return template.static_file(resp, req, "content/idmdevguide.pdf", - root=get_app_root(), - mimetype="application/pdf") - - @wrap_error - def get_wadl_contract(self, req): - resp = Response() - return template.static_file(resp, req, "identity.wadl", - root=get_app_root(), - mimetype="application/vnd.sun.wadl+xml") - - @wrap_error - def get_xsd_contract(self, req, xsd): - resp = Response() - return template.static_file(resp, req, "/xsd/" + xsd, - root=get_app_root(), - mimetype="application/xml") - - @wrap_error - def get_xsd_atom_contract(self, req, xsd): - resp = Response() - return template.static_file(resp, req, "/xsd/atom/" + xsd, - root=get_app_root(), - mimetype="application/xml") - -class MiscController(wsgi.Controller): - - def __init__(self, options): - self.options = options - - @wrap_error - def get_version_info(self, req): - - resp = Response() - resp.charset = 'UTF-8' - if is_xml_response(req): - resp_file = os.path.join(POSSIBLE_TOPDIR, - "keystone/content/version.xml.tpl") - resp.content_type = "application/xml" - else: - resp_file = os.path.join(POSSIBLE_TOPDIR, - "keystone/content/version.json.tpl") - resp.content_type = "application/json" - - hostname = req.environ.get("SERVER_NAME") - port = req.environ.get("SERVER_PORT") - - resp.unicode_body= template.template(resp_file, HOST=hostname, PORT=port, - VERSION_STATUS=VERSION_STATUS, - VERSION_DATE=VERSION_DATE) - return resp - - - -class AuthController(wsgi.Controller): - - def __init__(self, options): - self.options = options - self.request = None - - @wrap_error - def authenticate(self, req): - self.request = req - - creds = get_normalized_request_content(auth.PasswordCredentials, req) - return send_result(200, req, service.authenticate(creds)) - - @wrap_error - def validate_token(self, req, token_id): - - belongs_to = None - if "belongsTo" in req.GET: - belongs_to = req.GET["belongsTo"] - rval = service.validate_token(get_auth_token(req), token_id, belongs_to) - - return send_result(200, req, rval) - - @wrap_error - def delete_token(self, req, token_id): - return send_result(204, req, service.revoke_token(get_auth_token(req), token_id)) - - -class TenantController(wsgi.Controller): - - def __init__(self, options): - self.options = options - - @wrap_error - def create_tenant(self, req): - tenant = get_normalized_request_content(tenants.Tenant, req) - return send_result(201, req, - service.create_tenant(get_auth_token(req), tenant)) - - @wrap_error - def get_tenants(self, req): - marker = None - if "marker" in req.GET: - marker = req.GET["marker"] - - if "limit" in req.GET: - limit = req.GET["limit"] - else: - limit = 10 - - url = '%s://%s:%s%s' % (req.environ['wsgi.url_scheme'], - req.environ.get("SERVER_NAME"), - req.environ.get("SERVER_PORT"), - req.environ['PATH_INFO']) - - tenants = service.get_tenants(get_auth_token(req), marker, limit, url) - return send_result(200, req, tenants) - - - @wrap_error - def get_tenant(self, req, tenant_id): - tenant = service.get_tenant(get_auth_token(req), tenant_id) - return send_result(200, req, tenant) - - @wrap_error - def update_tenant(self, req, tenant_id): - tenant = get_normalized_request_content(tenants.Tenant, req) - rval = service.update_tenant(get_auth_token(req), tenant_id, tenant) - return send_result(200, req, rval) - - @wrap_error - def delete_tenant(self, req, tenant_id): - rval = service.delete_tenant(get_auth_token(req), tenant_id) - return send_result(204, req, rval) - - - - # Tenant Group Methods - @wrap_error - def create_tenant_group(self, req, tenant_id): - group = get_normalized_request_content(tenants.Group, req) - return send_result(201, req, - service.create_tenant_group(get_auth_token(req), \ - tenant_id, group)) - @wrap_error - def get_tenant_groups(self, req, tenant_id): - marker = None - if "marker" in req.GET: - marker = req.GET["marker"] - - if "limit" in req.GET: - limit = req.GET["limit"] - else: - limit = 10 - - url = '%s://%s:%s%s' % (req.environ['wsgi.url_scheme'], - req.environ.get("SERVER_NAME"), - req.environ.get("SERVER_PORT"), - req.environ['PATH_INFO']) - - groups = service.get_tenant_groups(get_auth_token(req), - tenant_id, marker, limit, url) - return send_result(200, req, groups) - - @wrap_error - def get_tenant_group(self, req, tenant_id, group_id): - tenant = service.get_tenant_group(get_auth_token(req), tenant_id, - group_id) - return send_result(200, req, tenant) - - @wrap_error - def update_tenant_group(self, req, tenant_id, group_id): - group = get_normalized_request_content(tenants.Group, req) - rval = service.update_tenant_group(get_auth_token(req),\ - tenant_id, group_id, group) - return send_result(200, req, rval) - - @wrap_error - def delete_tenant_group(self, req, tenant_id, group_id): - rval = service.delete_tenant_group(get_auth_token(req), tenant_id, - group_id) - return send_result(204, req, rval) - - @wrap_error - def add_user_tenant_group(self, req, tenant_id, group_id, user_id): - # TBD - # IDMDevguide clarification needed on this property - return None - - @wrap_error - def delete_user_tenant_group(self, req, tenant_id, group_id, user_id): - # TBD - # IDMDevguide clarification needed on this property - return None - - @wrap_error - def get_user_tenant_group(self, req, tenant_id, group_id, user_id): - # TBD - # IDMDevguide clarification needed on this property - return None - -class UserController(wsgi.Controller): - - def __init__(self, options): - self.options = options - - @wrap_error - def create_user(self, req, tenant_id): - user = get_normalized_request_content(users.User, req) - return send_result(201, req, - service.create_user(get_auth_token(req), tenant_id, user)) - - @wrap_error - def get_tenant_users(self, req, tenant_id): - marker = None - if "marker" in req.GET: - marker = req.GET["marker"] - if "limit" in req.GET: - limit = req.GET["limit"] - else: - limit = 10 - url = '%s://%s:%s%s' % (req.environ['wsgi.url_scheme'], - req.environ.get("SERVER_NAME"), - req.environ.get("SERVER_PORT"), - req.environ['PATH_INFO']) - users = service.get_tenant_users(get_auth_token(req), tenant_id, marker, limit, url) - return send_result(200, req, users) - - @wrap_error - def get_user_groups(self, req, tenant_id, user_id): - marker = None - if "marker" in req.GET: - marker = req.GET["marker"] - - if "limit" in req.GET: - limit = req.GET["limit"] - else: - limit = 10 - url = '%s://%s:%s%s' % (req.environ['wsgi.url_scheme'], - req.environ.get("SERVER_NAME"), - req.environ.get("SERVER_PORT"), - req.environ['PATH_INFO']) - - groups = service.get_user_groups(get_auth_token(), - tenant_id,user_id, marker, limit,url) - return send_result(200, groups) - - @wrap_error - def get_user(self, req, tenant_id, user_id): - user = service.get_user(get_auth_token(req), tenant_id, user_id) - return send_result(200, req, user) - - @wrap_error - def update_user(self, req, user_id, tenant_id): - user = get_normalized_request_content(users.User_Update, req) - rval = service.update_user(get_auth_token(req), user_id, user, tenant_id) - return send_result(200, req, rval) - - @wrap_error - def delete_user(self, req, user_id, tenant_id): - rval = service.delete_user(get_auth_token(req), user_id, tenant_id) - return send_result(204, req, rval) - - @wrap_error - def set_user_password(self, req, user_id, tenant_id): - user = get_normalized_request_content(users.User_Update, req) - rval = service.set_user_password(get_auth_token(req), user_id, user, tenant_id) - return send_result(204, req, rval) - - # To be checked with Abdul not finished yet - @wrap_error - def set_user_enabled(self, req, user_id, tenant_id): - user = get_normalized_request_content(users.User_Update, req) - rval = service.enable_disable_user(get_auth_token(req), user_id, user, tenant_id) - return send_result(204, req, rval) - - - -class GroupsController(wsgi.Controller): - - - def __init__(self, options): - self.options = options - - @wrap_error - def create_group(self, req): - group = get_normalized_request_content(tenants.Group, req) - return send_result(201, req, - service.create_global_group(get_auth_token(req), - group)) - @wrap_error - def get_groups(self, req): - marker = None - if "marker" in req.GET: - marker = req.GET["marker"] - - if "limit" in req.GET: - limit = req.GET["limit"] - else: - limit = 10 - - url = '%s://%s:%s%s' % (req.environ['wsgi.url_scheme'], - req.environ.get("SERVER_NAME"), - req.environ.get("SERVER_PORT"), - req.environ['PATH_INFO']) - groups = service.get_global_groups(get_auth_token(req), - marker, limit, url) - return send_result(200, req, groups) - - @wrap_error - def get_group(self, req, group_id): - tenant = service.get_global_group(get_auth_token(req), group_id) - return send_result(200, req, tenant) - - @wrap_error - def update_group(self, req, group_id): - group = get_normalized_request_content(tenants.Group, req) - rval = service.update_global_group(get_auth_token(req), - group_id, group) - return send_result(200, req, rval) - - @wrap_error - def delete_group(self, req, group_id): - rval = service.delete_global_group(get_auth_token(req), group_id) - return send_result(204, req, rval) - - @wrap_error - def get_users_group(self, req, group_id): - marker = None - if "marker" in req.GET: - marker = req.GET["marker"] - - if "limit" in req.GET: - limit = req.GET["limit"] - else: - limit = 10 - - url = '%s://%s:%s%s' % (req.environ['wsgi.url_scheme'], - req.environ.get("SERVER_NAME"), - req.environ.get("SERVER_PORT"), - req.environ['PATH_INFO']) - - users = service.get_users_global_group(get_auth_token(req), - group_id, marker, limit, url) - return send_result(200, req, users) - - @wrap_error - def add_user_group(self, req, group_id, user_id): - return send_result(201, req, - service.add_user_global_group(get_auth_token(req), - group_id, user_id)) - @wrap_error - def delete_user_group(self, req, group_id, user_id): - return send_result(204, req, - service.delete_user_global_group(get_auth_token(req), - group_id, user_id)) - -class KeystoneAPI(wsgi.Router): - """WSGI entry point for all Keystone Auth API requests.""" - - def __init__(self, options): - self.options = options - mapper = routes.Mapper() - - # Token Operations - auth_controller = AuthController(options) - mapper.connect("/v1.0/token", controller=auth_controller, action="authenticate") - mapper.connect("/v1.0/token/{token_id}", controller=auth_controller, - action="validate_token", conditions=dict(method=["GET"])) - mapper.connect("/v1.0/token/{token_id}", controller=auth_controller, - action="delete_token", conditions=dict(method=["DELETE"])) - - # Tenant Operations - tenant_controller = TenantController(options) - mapper.connect("/v1.0/tenants", controller=tenant_controller, - action="create_tenant", conditions=dict(method=["POST"])) - mapper.connect("/v1.0/tenants", controller=tenant_controller, - action="get_tenants", conditions=dict(method=["GET"])) - mapper.connect("/v1.0/tenants/{tenant_id}", controller=tenant_controller, - action="get_tenant", conditions=dict(method=["GET"])) - mapper.connect("/v1.0/tenants/{tenant_id}", controller=tenant_controller, - action="update_tenant", conditions=dict(method=["PUT"])) - mapper.connect("/v1.0/tenants/{tenant_id}", controller=tenant_controller, - action="delete_tenant", conditions=dict(method=["DELETE"])) - - # Tenant Group Operations - - mapper.connect("/v1.0/tenant/{tenant_id}/groups", controller=tenant_controller, - action="create_tenant_group", conditions=dict(method=["POST"])) - mapper.connect("/v1.0/tenant/{tenant_id}/groups", controller=tenant_controller, - action="get_tenant_groups", conditions=dict(method=["GET"])) - mapper.connect("/v1.0/tenant/{tenant_id}/groups/{group_id}", controller=tenant_controller, - action="get_tenant_group", conditions=dict(method=["GET"])) - mapper.connect("/v1.0/tenant/{tenant_id}/groups/{group_id}", controller=tenant_controller, - action="update_tenant_group", conditions=dict(method=["PUT"])) - mapper.connect("/v1.0/tenant/{tenant_id}/groups/{group_id}", controller=tenant_controller, - action="delete_tenant_group", conditions=dict(method=["DELETE"])) - - # User Operations - user_controller = UserController(options) - mapper.connect("/v1.0/tenants/{tenant_id}/users", controller=user_controller, - action="create_user", conditions=dict(method=["POST"])) - mapper.connect("/v1.0/tenants/{tenant_id}/users", controller=user_controller, - action="get_tenant_users", conditions=dict(method=["GET"])) - mapper.connect("/v1.0/tenants/{tenant_id}/users/{user_id}", controller=user_controller, - action="get_user", conditions=dict(method=["GET"])) - mapper.connect("/v1.0/tenants/{tenant_id}/users/{user_id}", controller=user_controller, - action="update_user", conditions=dict(method=["PUT"])) - mapper.connect("/v1.0/tenants/{tenant_id}/users/{user_id}", controller=user_controller, - action="delete_user", conditions=dict(method=["DELETE"])) - mapper.connect("/v1.0/tenants/{tenant_id}/users/{user_id}/password", controller=user_controller, - action="set_user_password", conditions=dict(method=["PUT"])) - - # Test this, test failed - mapper.connect("/v1.0/tenants/{tenant_id}/users/{user_id}/enabled", controller=user_controller, - action="set_user_enabled", conditions=dict(method=["PUT"])) - - #Global Groups - groups_controller = GroupsController(options) - mapper.connect("/v1.0/groups", controller=groups_controller, - action="create_group", conditions=dict(method=["POST"])) - mapper.connect("/v1.0/groups", controller=groups_controller, - action="get_groups", conditions=dict(method=["GET"])) - mapper.connect("/v1.0/groups/{group_id}", controller=groups_controller, - action="get_group", conditions=dict(method=["GET"])) - mapper.connect("/v1.0/groups/{group_id}", controller=groups_controller, - action="update_group", conditions=dict(method=["PUT"])) - mapper.connect("/v1.0/groups/{group_id}", controller=groups_controller, - action="delete_group", conditions=dict(method=["DELETE"])) - mapper.connect("/v1.0/groups/{group_id}/users/{user_id}", controller=groups_controller, - action="add_user_group", conditions=dict(method=["PUT"])) - mapper.connect("/v1.0/groups/{group_id}/users/{user_id}", controller=groups_controller, - action="delete_user_group", conditions=dict(method=["DELETE"])) - - #Not working yet, somebody who has touched its models, please handle - mapper.connect("/v1.0/groups/{group_id}/users", controller=groups_controller, - action="get_users_group", conditions=dict(method=["GET"])) - - - - # Miscellaneous Operations - misc_controller = MiscController(options) - mapper.connect("/v1.0/", controller=misc_controller, - action="get_version_info",conditions=dict(method=["GET"])) - mapper.connect("/v1.0", controller=misc_controller, - action="get_version_info",conditions=dict(method=["GET"])) - - # Static Files Controller - static_files_controller = StaticFilesController(options) - mapper.connect("/v1.0/idmdevguide.pdf", controller=static_files_controller, - action="get_pdf_contract",conditions=dict(method=["GET"])) - mapper.connect("/v1.0/identity.wadl", controller=static_files_controller, - action="get_identity_wadl",conditions=dict(method=["GET"])) - mapper.connect("/v1.0/xsd/{xsd}", controller=static_files_controller, - action="get_pdf_contract",conditions=dict(method=["GET"])) - mapper.connect("/v1.0/xsd/atom/{xsd}", controller=static_files_controller, - action="get_pdf_contract",conditions=dict(method=["GET"])) - - super(KeystoneAPI, self).__init__(mapper) - -def app_factory(global_conf, **local_conf): - """paste.deploy app factory for creating Glance API server apps""" - try: - conf = global_conf.copy() - conf.update(local_conf) - except Exception as err: - print err - return KeystoneAPI(conf) diff --git a/keystone/common/config.py b/keystone/common/config.py index 09baeed5..8e6dc047 100644 --- a/keystone/common/config.py +++ b/keystone/common/config.py @@ -68,7 +68,7 @@ def add_common_options(parser): :param parser: optparse.OptionParser """ help_text = "The following configuration options are common to "\ - "all glance programs." + "all keystone programs." group = optparse.OptionGroup(parser, "Common Options", help_text) group.add_option('-v', '--verbose', default=False, dest="verbose", @@ -180,16 +180,20 @@ def find_config_file(options, args): We search for the paste config file in the following order: * If --config-file option is used, use that * If args[0] is a file, use that - * Search for glance.conf in standard directories: + * Search for keystone.conf in standard directories: * . - * ~.glance/ + * ~.keystone/ * ~ - * /etc/glance + * /etc/keystone * /etc + :if no config file is given get from possible_topdir/etc/keystone.conf :retval Full path to config file, or None if no config file found """ - + POSSIBLE_TOPDIR = os.path.normpath(os.path.join(\ + os.path.abspath(sys.argv[0]), + os.pardir, + os.pardir)) fix_path = lambda p: os.path.abspath(os.path.expanduser(p)) if options.get('config_file'): if os.path.exists(options['config_file']): @@ -198,7 +202,7 @@ def find_config_file(options, args): if os.path.exists(args[0]): return fix_path(args[0]) - # Handle standard directory search for glance.conf + # Handle standard directory search for keystone.conf config_file_dirs = [fix_path(os.getcwd()), fix_path(os.path.join('~', '.keystone')), fix_path('~'), @@ -208,8 +212,17 @@ def find_config_file(options, args): for cfg_dir in config_file_dirs: cfg_file = os.path.join(cfg_dir, 'keystone.conf') if os.path.exists(cfg_file): - print cfg_file return cfg_file + else: + if os.path.exists(os.path.join(POSSIBLE_TOPDIR, 'etc', \ + 'keystone.conf')): + # For debug only + config_file = os.path.join(POSSIBLE_TOPDIR, 'etc', \ + 'keystone.conf') + + print "Running server from %s " % config_file + return os.path.join(POSSIBLE_TOPDIR, 'etc', \ + 'keystone.conf') def load_paste_config(app_name, options, args): @@ -220,11 +233,11 @@ def load_paste_config(app_name, options, args): We search for the paste config file in the following order: * If --config-file option is used, use that * If args[0] is a file, use that - * Search for glance.conf in standard directories: + * Search for keystone.conf in standard directories: * . - * ~.glance/ + * ~.keystone/ * ~ - * /etc/glance + * /etc/keystone * /etc :param app_name: Name of the application to load config for, or None. @@ -256,11 +269,11 @@ def load_paste_app(app_name, options, args): We search for the paste config file in the following order: * If --config-file option is used, use that * If args[0] is a file, use that - * Search for glance.conf in standard directories: + * Search for keystone.conf in standard directories: * . - * ~.glance/ + * ~.keystone/ * ~ - * /etc/glance + * /etc/keystone * /etc :param app_name: Name of the application to load diff --git a/keystone/server.py b/keystone/server.py old mode 100644 new mode 100755 index 22ee8887..6203dde4 --- a/keystone/server.py +++ b/keystone/server.py @@ -13,7 +13,6 @@ # implied. # See the License for the specific language governing permissions and # limitations under the License. -# Not yet PEP8 """ @@ -36,367 +35,605 @@ HTTP_AUTHORIZATION : basic auth password used to validate the connection HTTP_X_AUTHORIZATION: the client identity being passed in """ - import functools import logging import os import sys -import eventlet -from eventlet import wsgi +import httplib +import json -import bottle -from bottle import request -from bottle import response -from queryext import exthandler +import routes +from webob import Response +from webob import Request +from webob import descriptors +from webob.exc import (HTTPNotFound, + HTTPConflict, + HTTPBadRequest) -# If ../keystone/__init__.py exists, add ../ to Python search path, so that -# it will override what happens to be installed in /usr/(local/)lib/python... 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) -print POSSIBLE_TOPDIR + +from queryext import exthandler +from keystone.common import wsgi import keystone.logic.service as serv -import keystone.logic.types.auth as auth import keystone.logic.types.tenant as tenants +import keystone.logic.types.auth as auth import keystone.logic.types.fault as fault +import keystone.logic.types.user as users +import keystone.common.template as template + VERSION_STATUS = "ALPHA" VERSION_DATE = "2011-04-23T00:00:00Z" -bottle.debug(True) - service = serv.IDMService() -## -## Override error pages -## - - -@bottle.error(400) -@bottle.error(401) -@bottle.error(403) -@bottle.error(404) -@bottle.error(409) -@bottle.error(415) -@bottle.error(500) -@bottle.error(503) -def error_handler(err): - return err.output - -def is_xml_response(): - if not "Accept" in request.header: +def is_xml_response(req): + if not "Accept" in req.headers: return False - return request.header["Accept"] == "application/xml" + return req.content_type == "application/xml" def get_app_root(): return os.path.abspath(os.path.dirname(__file__)) -def send_result(code, result): - content = None - response.content_type = None - if result: - if is_xml_response(): - content = result.to_xml() - response.content_type = "application/xml" - else: - content = result.to_json() - response.content_type = "application/json" - response.status = code - if code > 399: - return bottle.abort(code, content) - return content - - -def get_normalized_request_content(model): - """initialize a model from json/xml contents of request body""" - - ctype = request.environ.get("CONTENT_TYPE") - if ctype == "application/xml": - ret = model.from_xml(request.body.read()) - elif ctype == "application/json": - ret = model.from_json(request.body.read()) - else: - raise fault.IDMFault("I don't understand the content type ", code=415) - return ret - - -def get_auth_token(): +def get_auth_token(req): auth_token = None - if "X-Auth-Token" in request.header: - auth_token = request.header["X-Auth-Token"] + if "X-Auth-Token" in req.headers: + auth_token = req.headers["X-Auth-Token"] return auth_token def wrap_error(func): @functools.wraps(func) def check_error(*args, **kwargs): + print '>>>>>>>>>>>>>>>>>>..' try: + return func(*args, **kwargs) + except Exception as err: if isinstance(err, fault.IDMFault): - send_result(err.code, err) + return send_error(err.code, kwargs['req'], err) else: logging.exception(err) - send_result(500, fault.IDMFault("Unhandled error", str(err))) + return send_error(500, kwargs['req'], fault.IDMFault("Unhandled error", str(err))) return check_error -@bottle.route('/v1.0', method='GET') -@bottle.route('/v1.0/', method='GET') -@wrap_error -def get_version_info(): - if is_xml_response(): - resp_file = os.path.join(POSSIBLE_TOPDIR, - "keystone/content/version.xml.tpl") - response.content_type = "application/xml" - else: - resp_file = os.path.join(POSSIBLE_TOPDIR, - "keystone/content/version.json.tpl") - response.content_type = "application/json" - hostname = request.environ.get("SERVER_NAME") - port = request.environ.get("SERVER_PORT") - return bottle.template(resp_file, HOST=hostname, PORT=port, - VERSION_STATUS=VERSION_STATUS, - VERSION_DATE=VERSION_DATE) - -## -## Version links: -## - - -@bottle.route('/v1.0/idmdevguide.pdf', method='GET') -@wrap_error -def get_pdf_contract(): - return bottle.static_file("content/idmdevguide.pdf", - root=get_app_root(), - mimetype="application/pdf") - - -@bottle.route('/v1.0/identity.wadl', method='GET') -@wrap_error -def get_wadl_contract(): - return bottle.static_file("identity.wadl", - root=get_app_root(), - mimetype="application/vnd.sun.wadl+xml") - - -@bottle.route('/v1.0/xsd/:xsd', method='GET') -@wrap_error -def get_xsd_contract(xsd): - return bottle.static_file("/xsd/" + xsd, - root=get_app_root(), - mimetype="application/xml") - - -@bottle.route('/v1.0/xsd/atom/:xsd', method='GET') -@wrap_error -def get_xsd_atom_contract(xsd): - return bottle.static_file("/xsd/atom/" + xsd, - root=get_app_root(), - mimetype="application/xml") - -## -## Token Operations -## - - -@bottle.route('/v1.0/token', method='POST') -@wrap_error -def authenticate(): - creds = get_normalized_request_content(auth.PasswordCredentials) - return send_result(200, service.authenticate(creds)) - - -@bottle.route('/v1.0/token/:token_id', method='GET') -@wrap_error -def validate_token(token_id): - belongs_to = None - if "belongsTo" in request.GET: - belongs_to = request.GET["belongsTo"] - rval = service.validate_token(get_auth_token(), token_id, belongs_to) - return send_result(200, rval) - - -@bottle.route('/v1.0/token/:token_id', method='DELETE') -@wrap_error -def delete_token(token_id): - return send_result(204, - service.revoke_token(get_auth_token(), token_id)) - -## -## Tenant Operations -## - - -@bottle.route('/v1.0/tenants', method='POST') -@wrap_error -def create_tenant(): - tenant = get_normalized_request_content(tenants.Tenant) - return send_result(201, - service.create_tenant(get_auth_token(), tenant)) - - -# -# Tenants Pagination Script Added -@bottle.route('/v1.0/tenants', method='GET') -@wrap_error -def get_tenants(): - marker = None - if "marker" in request.GET: - marker = request.GET["marker"] - - if "limit" in request.GET: - limit = request.GET["limit"] - else: - limit = 10 - - url = '%s://%s:%s%s' % (request.environ['wsgi.url_scheme'], - request.environ.get("SERVER_NAME"), - request.environ.get("SERVER_PORT"), - request.environ['PATH_INFO']) - - tenants = service.get_tenants(get_auth_token(), marker, limit, url) - return send_result(200, tenants) - - -@bottle.route('/v1.0/tenants/:tenant_id', method='GET') -@wrap_error -def get_tenant(tenant_id): - tenant = service.get_tenant(get_auth_token(), tenant_id) - return send_result(200, tenant) - - -@bottle.route('/v1.0/tenants/:tenant_id', method='PUT') -@wrap_error -def update_tenant(tenant_id): - tenant = get_normalized_request_content(tenants.Tenant) - rval = service.update_tenant(get_auth_token(), tenant_id, tenant) - return send_result(200, rval) - - -@bottle.route('/v1.0/tenants/:tenant_id', method='DELETE') -@wrap_error -def delete_tenant(tenant_id): - rval = service.delete_tenant(get_auth_token(), tenant_id) - return send_result(204, rval) - - -## -## Tenant Groups -## - -@bottle.route('/v1.0/tenant/:tenantId/groups', method='POST') -@wrap_error -def create_tenant_group(tenantId): - group = get_normalized_request_content(tenants.Group) - return send_result(201, - service.create_tenant_group(get_auth_token(), \ - tenantId, group)) - - -@bottle.route('/v1.0/tenant/:tenantId/groups', method='GET') -@wrap_error -def get_tenant_groups(tenantId): - marker = None - if "marker" in request.GET: - marker = request.GET["marker"] - - if "limit" in request.GET: - limit = request.GET["limit"] +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) + elif req.content_type == "application/json": + + ret = model.from_json(req.body) else: - limit = 10 - - url = '%s://%s:%s%s' % (request.environ['wsgi.url_scheme'], - request.environ.get("SERVER_NAME"), - request.environ.get("SERVER_PORT"), - request.environ['PATH_INFO']) - - groups = service.get_tenant_groups(get_auth_token(), - tenantId, marker, limit, url) - return send_result(200, groups) - - -@bottle.route('/v1.0/tenant/:tenantId/groups/:groupId', method='GET') -@wrap_error -def get_tenant_group(tenantId, groupId): - tenant = service.get_tenant_group(get_auth_token(), tenantId, groupId) - return send_result(200, tenant) - - -@bottle.route('/v1.0/tenant/:tenantId/groups/:groupId', method='PUT') -@wrap_error -def update_tenant_group(tenantId, groupId): - group = get_normalized_request_content(tenants.Group) - rval = service.update_tenant_group(get_auth_token(),\ - tenantId, groupId, group) - return send_result(200, rval) - + + raise fault.IDMFault("I don't understand the content type ", code=415) + return ret -@bottle.route('/v1.0/tenant/:tenantId/groups/:groupId', method='DELETE') -@wrap_error -def delete_tenant_group(tenantId, groupId): - rval = service.delete_tenant_group(get_auth_token(), tenantId, groupId) - return send_result(204, rval) +def send_error(code, req, result): + content = None + 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" + resp.content_type_params={'charset' : 'UTF-8'} + resp.unicode_body = content.decode('UTF-8') + + return resp -@bottle.route('/v1.0/tenants/:tenantId/groups/:groupId/users', method='GET') -@wrap_error -def get_users_tenant_group(tenantId, groupId): - marker = None - if "marker" in request.GET: - marker = request.GET["marker"] - if "limit" in request.GET: - limit = request.GET["limit"] - else: - limit = 10 +def send_result(code, req, result): + content = None + resp = Response() + resp.headers['content-type'] = None + resp.status = code + if code > 399: + return resp + + 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" - url = '%s://%s:%s%s' % (request.environ['wsgi.url_scheme'],\ - request.environ.get("SERVER_NAME"),\ - request.environ.get("SERVER_PORT"),\ - request.environ['PATH_INFO']) + resp.content_type_params={'charset' : 'UTF-8'} + resp.unicode_body = content.decode('UTF-8') - users = service.get_users_tenant_group(get_auth_token(),\ - tenantId, groupId, marker, limit, url) - return send_result(200, users) + return resp +class StaticFilesController(wsgi.Controller): -## -## Extensions -## + def __init__(self, options): + self.options = options + + @wrap_error + def get_pdf_contract(self, req): + resp = Response() + return template.static_file(resp, req, "content/idmdevguide.pdf", + root=get_app_root(), + mimetype="application/pdf") -@bottle.route('/v1.0/extensions', method='GET') -@wrap_error -def get_extensions(): - if is_xml_response(): - resp_file = "content/extensions.xml" - mimetype = "application/xml" - else: - resp_file = "content/extensions.json" - mimetype = "application/json" - return bottle.static_file(resp_file, + @wrap_error + def get_wadl_contract(self, req): + resp = Response() + return template.static_file(resp, req, "identity.wadl", root=get_app_root(), - mimetype=mimetype) - - -@bottle.route('/v1.0/extensions/:ext_alias', method='GET') -@wrap_error -def get_extension(ext_alias): - # - # Todo: Define some extensions :-) - # - raise fault.ItemNotFoundFault("The extension is not found") + mimetype="application/vnd.sun.wadl+xml") + @wrap_error + def get_xsd_contract(self, req, xsd): + resp = Response() + return template.static_file(resp, req, "/xsd/" + xsd, + root=get_app_root(), + mimetype="application/xml") -def start_server(port=8080): - app = exthandler.UrlExtensionFilter(bottle.default_app(), None) - wsgi.server(eventlet.listen(('', port)), app) + @wrap_error + def get_xsd_atom_contract(self, req, xsd): + resp = Response() + return template.static_file(resp, req, "/xsd/atom/" + xsd, + root=get_app_root(), + mimetype="application/xml") -if __name__ == "__main__": - start_server() +class MiscController(wsgi.Controller): + + def __init__(self, options): + self.options = options + + @wrap_error + def get_version_info(self, req): + + resp = Response() + resp.charset = 'UTF-8' + if is_xml_response(req): + resp_file = os.path.join(POSSIBLE_TOPDIR, + "keystone/content/version.xml.tpl") + resp.content_type = "application/xml" + else: + resp_file = os.path.join(POSSIBLE_TOPDIR, + "keystone/content/version.json.tpl") + resp.content_type = "application/json" + + hostname = req.environ.get("SERVER_NAME") + port = req.environ.get("SERVER_PORT") + + resp.unicode_body= template.template(resp_file, HOST=hostname, PORT=port, + VERSION_STATUS=VERSION_STATUS, + VERSION_DATE=VERSION_DATE) + return resp + + + +class AuthController(wsgi.Controller): + + def __init__(self, options): + self.options = options + self.request = None + + @wrap_error + def authenticate(self, req): + self.request = req + + creds = get_normalized_request_content(auth.PasswordCredentials, req) + return send_result(200, req, service.authenticate(creds)) + + @wrap_error + def validate_token(self, req, token_id): + + belongs_to = None + if "belongsTo" in req.GET: + belongs_to = req.GET["belongsTo"] + rval = service.validate_token(get_auth_token(req), token_id, belongs_to) + + return send_result(200, req, rval) + + @wrap_error + def delete_token(self, req, token_id): + return send_result(204, req, service.revoke_token(get_auth_token(req), token_id)) + + +class TenantController(wsgi.Controller): + + def __init__(self, options): + self.options = options + + @wrap_error + def create_tenant(self, req): + tenant = get_normalized_request_content(tenants.Tenant, req) + return send_result(201, req, + service.create_tenant(get_auth_token(req), tenant)) + + @wrap_error + def get_tenants(self, req): + marker = None + if "marker" in req.GET: + marker = req.GET["marker"] + + if "limit" in req.GET: + limit = req.GET["limit"] + else: + limit = 10 + + url = '%s://%s:%s%s' % (req.environ['wsgi.url_scheme'], + req.environ.get("SERVER_NAME"), + req.environ.get("SERVER_PORT"), + req.environ['PATH_INFO']) + + tenants = service.get_tenants(get_auth_token(req), marker, limit, url) + return send_result(200, req, tenants) + + + @wrap_error + def get_tenant(self, req, tenant_id): + tenant = service.get_tenant(get_auth_token(req), tenant_id) + return send_result(200, req, tenant) + + @wrap_error + def update_tenant(self, req, tenant_id): + tenant = get_normalized_request_content(tenants.Tenant, req) + rval = service.update_tenant(get_auth_token(req), tenant_id, tenant) + return send_result(200, req, rval) + + @wrap_error + def delete_tenant(self, req, tenant_id): + rval = service.delete_tenant(get_auth_token(req), tenant_id) + return send_result(204, req, rval) + + + + # Tenant Group Methods + @wrap_error + def create_tenant_group(self, req, tenant_id): + group = get_normalized_request_content(tenants.Group, req) + return send_result(201, req, + service.create_tenant_group(get_auth_token(req), \ + tenant_id, group)) + @wrap_error + def get_tenant_groups(self, req, tenant_id): + marker = None + if "marker" in req.GET: + marker = req.GET["marker"] + + if "limit" in req.GET: + limit = req.GET["limit"] + else: + limit = 10 + + url = '%s://%s:%s%s' % (req.environ['wsgi.url_scheme'], + req.environ.get("SERVER_NAME"), + req.environ.get("SERVER_PORT"), + req.environ['PATH_INFO']) + + groups = service.get_tenant_groups(get_auth_token(req), + tenant_id, marker, limit, url) + return send_result(200, req, groups) + + @wrap_error + def get_tenant_group(self, req, tenant_id, group_id): + tenant = service.get_tenant_group(get_auth_token(req), tenant_id, + group_id) + return send_result(200, req, tenant) + + @wrap_error + def update_tenant_group(self, req, tenant_id, group_id): + group = get_normalized_request_content(tenants.Group, req) + rval = service.update_tenant_group(get_auth_token(req),\ + tenant_id, group_id, group) + return send_result(200, req, rval) + + @wrap_error + def delete_tenant_group(self, req, tenant_id, group_id): + rval = service.delete_tenant_group(get_auth_token(req), tenant_id, + group_id) + return send_result(204, req, rval) + + @wrap_error + def add_user_tenant_group(self, req, tenant_id, group_id, user_id): + # TBD + # IDMDevguide clarification needed on this property + return None + + @wrap_error + def delete_user_tenant_group(self, req, tenant_id, group_id, user_id): + # TBD + # IDMDevguide clarification needed on this property + return None + + @wrap_error + def get_user_tenant_group(self, req, tenant_id, group_id, user_id): + # TBD + # IDMDevguide clarification needed on this property + return None + +class UserController(wsgi.Controller): + + def __init__(self, options): + self.options = options + + @wrap_error + def create_user(self, req, tenant_id): + user = get_normalized_request_content(users.User, req) + return send_result(201, req, + service.create_user(get_auth_token(req), tenant_id, user)) + + @wrap_error + def get_tenant_users(self, req, tenant_id): + marker = None + if "marker" in req.GET: + marker = req.GET["marker"] + if "limit" in req.GET: + limit = req.GET["limit"] + else: + limit = 10 + url = '%s://%s:%s%s' % (req.environ['wsgi.url_scheme'], + req.environ.get("SERVER_NAME"), + req.environ.get("SERVER_PORT"), + req.environ['PATH_INFO']) + users = service.get_tenant_users(get_auth_token(req), tenant_id, marker, limit, url) + return send_result(200, req, users) + + @wrap_error + def get_user_groups(self, req, tenant_id, user_id): + marker = None + if "marker" in req.GET: + marker = req.GET["marker"] + + if "limit" in req.GET: + limit = req.GET["limit"] + else: + limit = 10 + url = '%s://%s:%s%s' % (req.environ['wsgi.url_scheme'], + req.environ.get("SERVER_NAME"), + req.environ.get("SERVER_PORT"), + req.environ['PATH_INFO']) + + groups = service.get_user_groups(get_auth_token(), + tenant_id,user_id, marker, limit,url) + return send_result(200, groups) + + @wrap_error + def get_user(self, req, tenant_id, user_id): + user = service.get_user(get_auth_token(req), tenant_id, user_id) + return send_result(200, req, user) + + @wrap_error + def update_user(self, req, user_id, tenant_id): + user = get_normalized_request_content(users.User_Update, req) + rval = service.update_user(get_auth_token(req), user_id, user, tenant_id) + return send_result(200, req, rval) + + @wrap_error + def delete_user(self, req, user_id, tenant_id): + rval = service.delete_user(get_auth_token(req), user_id, tenant_id) + return send_result(204, req, rval) + + @wrap_error + def set_user_password(self, req, user_id, tenant_id): + user = get_normalized_request_content(users.User_Update, req) + rval = service.set_user_password(get_auth_token(req), user_id, user, tenant_id) + return send_result(204, req, rval) + + # To be checked with Abdul not finished yet + @wrap_error + def set_user_enabled(self, req, user_id, tenant_id): + user = get_normalized_request_content(users.User_Update, req) + rval = service.enable_disable_user(get_auth_token(req), user_id, user, tenant_id) + return send_result(204, req, rval) + + + +class GroupsController(wsgi.Controller): + + + def __init__(self, options): + self.options = options + + @wrap_error + def create_group(self, req): + group = get_normalized_request_content(tenants.Group, req) + return send_result(201, req, + service.create_global_group(get_auth_token(req), + group)) + @wrap_error + def get_groups(self, req): + marker = None + if "marker" in req.GET: + marker = req.GET["marker"] + + if "limit" in req.GET: + limit = req.GET["limit"] + else: + limit = 10 + + url = '%s://%s:%s%s' % (req.environ['wsgi.url_scheme'], + req.environ.get("SERVER_NAME"), + req.environ.get("SERVER_PORT"), + req.environ['PATH_INFO']) + groups = service.get_global_groups(get_auth_token(req), + marker, limit, url) + return send_result(200, req, groups) + + @wrap_error + def get_group(self, req, group_id): + tenant = service.get_global_group(get_auth_token(req), group_id) + return send_result(200, req, tenant) + + @wrap_error + def update_group(self, req, group_id): + group = get_normalized_request_content(tenants.Group, req) + rval = service.update_global_group(get_auth_token(req), + group_id, group) + return send_result(200, req, rval) + + @wrap_error + def delete_group(self, req, group_id): + rval = service.delete_global_group(get_auth_token(req), group_id) + return send_result(204, req, rval) + + @wrap_error + def get_users_group(self, req, group_id): + marker = None + if "marker" in req.GET: + marker = req.GET["marker"] + + if "limit" in req.GET: + limit = req.GET["limit"] + else: + limit = 10 + + url = '%s://%s:%s%s' % (req.environ['wsgi.url_scheme'], + req.environ.get("SERVER_NAME"), + req.environ.get("SERVER_PORT"), + req.environ['PATH_INFO']) + + users = service.get_users_global_group(get_auth_token(req), + group_id, marker, limit, url) + return send_result(200, req, users) + + @wrap_error + def add_user_group(self, req, group_id, user_id): + return send_result(201, req, + service.add_user_global_group(get_auth_token(req), + group_id, user_id)) + @wrap_error + def delete_user_group(self, req, group_id, user_id): + return send_result(204, req, + service.delete_user_global_group(get_auth_token(req), + group_id, user_id)) + +class KeystoneAPI(wsgi.Router): + """WSGI entry point for all Keystone Auth API requests.""" + + def __init__(self, options): + self.options = options + mapper = routes.Mapper() + + # Token Operations + auth_controller = AuthController(options) + mapper.connect("/v1.0/token", controller=auth_controller, action="authenticate") + mapper.connect("/v1.0/token/{token_id}", controller=auth_controller, + action="validate_token", conditions=dict(method=["GET"])) + mapper.connect("/v1.0/token/{token_id}", controller=auth_controller, + action="delete_token", conditions=dict(method=["DELETE"])) + + # Tenant Operations + tenant_controller = TenantController(options) + mapper.connect("/v1.0/tenants", controller=tenant_controller, + action="create_tenant", conditions=dict(method=["POST"])) + mapper.connect("/v1.0/tenants", controller=tenant_controller, + action="get_tenants", conditions=dict(method=["GET"])) + mapper.connect("/v1.0/tenants/{tenant_id}", controller=tenant_controller, + action="get_tenant", conditions=dict(method=["GET"])) + mapper.connect("/v1.0/tenants/{tenant_id}", controller=tenant_controller, + action="update_tenant", conditions=dict(method=["PUT"])) + mapper.connect("/v1.0/tenants/{tenant_id}", controller=tenant_controller, + action="delete_tenant", conditions=dict(method=["DELETE"])) + + # Tenant Group Operations + + mapper.connect("/v1.0/tenant/{tenant_id}/groups", controller=tenant_controller, + action="create_tenant_group", conditions=dict(method=["POST"])) + mapper.connect("/v1.0/tenant/{tenant_id}/groups", controller=tenant_controller, + action="get_tenant_groups", conditions=dict(method=["GET"])) + mapper.connect("/v1.0/tenant/{tenant_id}/groups/{group_id}", controller=tenant_controller, + action="get_tenant_group", conditions=dict(method=["GET"])) + mapper.connect("/v1.0/tenant/{tenant_id}/groups/{group_id}", controller=tenant_controller, + action="update_tenant_group", conditions=dict(method=["PUT"])) + mapper.connect("/v1.0/tenant/{tenant_id}/groups/{group_id}", controller=tenant_controller, + action="delete_tenant_group", conditions=dict(method=["DELETE"])) + + # User Operations + user_controller = UserController(options) + mapper.connect("/v1.0/tenants/{tenant_id}/users", controller=user_controller, + action="create_user", conditions=dict(method=["POST"])) + mapper.connect("/v1.0/tenants/{tenant_id}/users", controller=user_controller, + action="get_tenant_users", conditions=dict(method=["GET"])) + mapper.connect("/v1.0/tenants/{tenant_id}/users/{user_id}", controller=user_controller, + action="get_user", conditions=dict(method=["GET"])) + mapper.connect("/v1.0/tenants/{tenant_id}/users/{user_id}", controller=user_controller, + action="update_user", conditions=dict(method=["PUT"])) + mapper.connect("/v1.0/tenants/{tenant_id}/users/{user_id}", controller=user_controller, + action="delete_user", conditions=dict(method=["DELETE"])) + mapper.connect("/v1.0/tenants/{tenant_id}/users/{user_id}/password", controller=user_controller, + action="set_user_password", conditions=dict(method=["PUT"])) + + # Test this, test failed + mapper.connect("/v1.0/tenants/{tenant_id}/users/{user_id}/enabled", controller=user_controller, + action="set_user_enabled", conditions=dict(method=["PUT"])) + + #Global Groups + groups_controller = GroupsController(options) + mapper.connect("/v1.0/groups", controller=groups_controller, + action="create_group", conditions=dict(method=["POST"])) + mapper.connect("/v1.0/groups", controller=groups_controller, + action="get_groups", conditions=dict(method=["GET"])) + mapper.connect("/v1.0/groups/{group_id}", controller=groups_controller, + action="get_group", conditions=dict(method=["GET"])) + mapper.connect("/v1.0/groups/{group_id}", controller=groups_controller, + action="update_group", conditions=dict(method=["PUT"])) + mapper.connect("/v1.0/groups/{group_id}", controller=groups_controller, + action="delete_group", conditions=dict(method=["DELETE"])) + mapper.connect("/v1.0/groups/{group_id}/users/{user_id}", controller=groups_controller, + action="add_user_group", conditions=dict(method=["PUT"])) + mapper.connect("/v1.0/groups/{group_id}/users/{user_id}", controller=groups_controller, + action="delete_user_group", conditions=dict(method=["DELETE"])) + + #Not working yet, somebody who has touched its models, please handle + mapper.connect("/v1.0/groups/{group_id}/users", controller=groups_controller, + action="get_users_group", conditions=dict(method=["GET"])) + + + + # Miscellaneous Operations + misc_controller = MiscController(options) + mapper.connect("/v1.0/", controller=misc_controller, + action="get_version_info",conditions=dict(method=["GET"])) + mapper.connect("/v1.0", controller=misc_controller, + action="get_version_info",conditions=dict(method=["GET"])) + + # Static Files Controller + static_files_controller = StaticFilesController(options) + mapper.connect("/v1.0/idmdevguide.pdf", controller=static_files_controller, + action="get_pdf_contract",conditions=dict(method=["GET"])) + mapper.connect("/v1.0/identity.wadl", controller=static_files_controller, + action="get_identity_wadl",conditions=dict(method=["GET"])) + mapper.connect("/v1.0/xsd/{xsd}", controller=static_files_controller, + action="get_pdf_contract",conditions=dict(method=["GET"])) + mapper.connect("/v1.0/xsd/atom/{xsd}", controller=static_files_controller, + action="get_pdf_contract",conditions=dict(method=["GET"])) + + super(KeystoneAPI, self).__init__(mapper) + +def app_factory(global_conf, **local_conf): + """paste.deploy app factory for creating Glance API server apps""" + try: + conf = global_conf.copy() + conf.update(local_conf) + except Exception as err: + print err + return KeystoneAPI(conf) diff --git a/setup.py b/setup.py index f5ab870a..41f326cd 100644 --- a/setup.py +++ b/setup.py @@ -31,13 +31,13 @@ setup( include_package_data=True, packages=find_packages(exclude=['test', 'bin']), scripts=['bin/keystone'] - zip_safe=False, - install_requires=['setuptools'], - entry_points={ - 'paste.app_factory': ['main=identity:app_factory'], - 'paste.filter_factory': [ - 'papiauth=keystone:papiauth_factory', - 'tokenauth=keystone:tokenauth_factory', - ], - }, +# zip_safe=False, +# install_requires=['setuptools'], +# entry_points={ +# 'paste.app_factory': ['main=identity:app_factory'], +# 'paste.filter_factory': [ +# 'papiauth=keystone:papiauth_factory', +# 'tokenauth=keystone:tokenauth_factory', +# ], +# }, ) diff --git a/test/unit/test_identity.py b/test/unit/test_identity.py index e6079366..adbd26db 100644 --- a/test/unit/test_identity.py +++ b/test/unit/test_identity.py @@ -3,7 +3,7 @@ import sys # Need to access identity module sys.path.append(os.path.abspath(os.path.join(os.path.abspath(__file__), '..', '..', '..', '..', 'keystone'))) -from keystone import auth_server +from keystone import server import unittest from webtest import TestApp import httplib2 -- cgit