diff options
Diffstat (limited to 'utils')
16 files changed, 212 insertions, 13 deletions
diff --git a/utils/test/testapi/3rd_party/static/testapi-ui/components/home/home.html b/utils/test/testapi/3rd_party/static/testapi-ui/components/home/home.html index 04f64d52b..47d747fd8 100644 --- a/utils/test/testapi/3rd_party/static/testapi-ui/components/home/home.html +++ b/utils/test/testapi/3rd_party/static/testapi-ui/components/home/home.html @@ -1,6 +1,6 @@ <div class="jumbotron openstack-intro"> <div class="pull-right right openstack-intro__logo"> - <img src="swagger/testapi-ui/assets/img/opnfv-logo.png" alt="OPNFV"> + <img src="testapi-ui/assets/img/opnfv-logo.png" alt="OPNFV"> </div> <div class="pull-left left openstack-intro__content"> <h1>Results Collection</h1> diff --git a/utils/test/testapi/3rd_party/static/testapi-ui/config.json b/utils/test/testapi/3rd_party/static/testapi-ui/config.json index c88d46c25..5d48c7b12 100644 --- a/utils/test/testapi/3rd_party/static/testapi-ui/config.json +++ b/utils/test/testapi/3rd_party/static/testapi-ui/config.json @@ -1 +1 @@ -{"testapiApiUrl": "http://10.62.105.17:9711"} +{"testapiApiUrl": "http://localhost:8000/api/v1"} diff --git a/utils/test/testapi/3rd_party/static/testapi-ui/shared/header/header.html b/utils/test/testapi/3rd_party/static/testapi-ui/shared/header/header.html index 78361b8a5..f2c49e86f 100644 --- a/utils/test/testapi/3rd_party/static/testapi-ui/shared/header/header.html +++ b/utils/test/testapi/3rd_party/static/testapi-ui/shared/header/header.html @@ -1,4 +1,4 @@ -<div class="heading"><a ui-sref="home"><img src="swagger/testapi-ui/assets/img/testapi-logo.png" alt="TestAPI"></a> +<div class="heading"><a ui-sref="home"><img src="testapi-ui/assets/img/testapi-logo.png" alt="TestAPI"></a> TestAPI </div> <nav class="navbar navbar-default" role="navigation" ng-controller="HeaderController as header"> diff --git a/utils/test/testapi/etc/config.ini b/utils/test/testapi/etc/config.ini index 77cc6c6ee..692e48897 100644 --- a/utils/test/testapi/etc/config.ini +++ b/utils/test/testapi/etc/config.ini @@ -8,6 +8,7 @@ dbname = test_results_collection [api] # Listening port +url = http://localhost:8000/api/v1 port = 8000 # With debug_on set to true, error traces will be shown in HTTP responses debug = True @@ -15,3 +16,52 @@ authenticate = False [swagger] base_url = http://localhost:8000 + +[ui] +url = http://localhost:8000 + +[osid] + +# OpenStackID Auth Server URI. (string value) +openstack_openid_endpoint = https://openstackid.org/accounts/openid2 + +# OpenStackID logout URI. (string value) +openid_logout_endpoint = https://openstackid.org/accounts/user/logout + +# Interaction mode. Specifies whether Openstack Id IdP may interact +# with the user to determine the outcome of the request. (string +# value) +openid_mode = checkid_setup + +# Protocol version. Value identifying the OpenID protocol version +# being used. This value should be "http://specs.openid.net/auth/2.0". +# (string value) +openid_ns = http://specs.openid.net/auth/2.0 + +# Return endpoint in Refstack's API. Value indicating the endpoint +# where the user should be returned to after signing in. Openstack Id +# Idp only supports HTTPS address types. (string value) +openid_return_to = /api/v1/auth/signin_return + +# Claimed identifier. This value must be set to +# "http://specs.openid.net/auth/2.0/identifier_select". or to user +# claimed identity (user local identifier or user owned identity [ex: +# custom html hosted on a owned domain set to html discover]). (string +# value) +openid_claimed_id = http://specs.openid.net/auth/2.0/identifier_select + +# Alternate identifier. This value must be set to +# http://specs.openid.net/auth/2.0/identifier_select. (string value) +openid_identity = http://specs.openid.net/auth/2.0/identifier_select + +# Indicates request for user attribute information. This value must be +# set to "http://openid.net/extensions/sreg/1.1". (string value) +openid_ns_sreg = http://openid.net/extensions/sreg/1.1 + +# Comma-separated list of field names which, if absent from the +# response, will prevent the Consumer from completing the registration +# without End User interation. The field names are those that are +# specified in the Response Format, with the "openid.sreg." prefix +# removed. Valid values include: "country", "email", "firstname", +# "language", "lastname" (string value) +openid_sreg_required = email,fullname diff --git a/utils/test/testapi/opnfv_testapi/cmd/server.py b/utils/test/testapi/opnfv_testapi/cmd/server.py index 2696bb397..545d5e367 100644 --- a/utils/test/testapi/opnfv_testapi/cmd/server.py +++ b/utils/test/testapi/opnfv_testapi/cmd/server.py @@ -64,7 +64,8 @@ def make_app(): url_mappings.mappings, db=get_db(), debug=CONF.api_debug, - auth=CONF.api_authenticate + auth=CONF.api_authenticate, + cookie_secret='opnfv-testapi', ) diff --git a/utils/test/testapi/opnfv_testapi/common/check.py b/utils/test/testapi/opnfv_testapi/common/check.py index 4d9902cd0..67e8fbd40 100644 --- a/utils/test/testapi/opnfv_testapi/common/check.py +++ b/utils/test/testapi/opnfv_testapi/common/check.py @@ -61,7 +61,7 @@ def no_body(xstep): def miss_fields(xstep): @functools.wraps(xstep) def wrap(self, *args, **kwargs): - fields = kwargs.get('miss_fields') + fields = kwargs.pop('miss_fields', []) if fields: for miss in fields: miss_data = self.json_args.get(miss) @@ -75,7 +75,7 @@ def miss_fields(xstep): def carriers_exist(xstep): @functools.wraps(xstep) def wrap(self, *args, **kwargs): - carriers = kwargs.get('carriers') + carriers = kwargs.pop('carriers', {}) if carriers: for table, query in carriers: exist = yield self._eval_db_find_one(query(), table) @@ -102,7 +102,7 @@ def new_not_exists(xstep): def updated_one_not_exist(xstep): @functools.wraps(xstep) def wrap(self, data, *args, **kwargs): - db_keys = kwargs.get('db_keys') + db_keys = kwargs.pop('db_keys', []) query = self._update_query(db_keys, data) if query: to_data = yield self._eval_db_find_one(query) diff --git a/utils/test/testapi/opnfv_testapi/resources/handlers.py b/utils/test/testapi/opnfv_testapi/resources/handlers.py index dbf94eb75..2fc31ca45 100644 --- a/utils/test/testapi/opnfv_testapi/resources/handlers.py +++ b/utils/test/testapi/opnfv_testapi/resources/handlers.py @@ -85,7 +85,8 @@ class GenericApiHandler(web.RequestHandler): """ data = self.table_cls.from_dict(self.json_args) for k, v in kwargs.iteritems(): - data.__setattr__(k, v) + if k != 'query': + data.__setattr__(k, v) if self.table != 'results': data.creation_date = datetime.now() @@ -188,6 +189,14 @@ class GenericApiHandler(web.RequestHandler): table = self.table return self._eval_db(table, 'find_one', query) + def db_save(self, collection, data): + self._eval_db(collection, 'insert', data, check_keys=False) + + def db_find_one(self, query, collection=None): + if not collection: + collection = self.table + return self._eval_db(collection, 'find_one', query) + class VersionHandler(GenericApiHandler): @swagger.operation(nickname='listAllVersions') diff --git a/utils/test/testapi/opnfv_testapi/router/url_mappings.py b/utils/test/testapi/opnfv_testapi/router/url_mappings.py index ebe59941a..aea85a4c4 100644 --- a/utils/test/testapi/opnfv_testapi/router/url_mappings.py +++ b/utils/test/testapi/opnfv_testapi/router/url_mappings.py @@ -15,11 +15,12 @@ from opnfv_testapi.resources import project_handlers from opnfv_testapi.resources import result_handlers from opnfv_testapi.resources import scenario_handlers from opnfv_testapi.resources import testcase_handlers -import opnfv_testapi.resources.ui_handlers +from opnfv_testapi.ui import root +from opnfv_testapi.ui.auth import sign +from opnfv_testapi.ui.auth import user mappings = [ # GET /versions => GET API version - (r'/', opnfv_testapi.resources.ui_handlers.UIHandler), (r"/versions", handlers.VersionHandler), # few examples: @@ -54,7 +55,13 @@ mappings = [ (r"/api/v1/scenarios/([^/]+)", scenario_handlers.ScenarioGURHandler), # static path - (r'/(.*\.(css|png|gif|js|html|json))', + (r'/(.*\.(css|png|gif|js|html|json|map))', tornado.web.StaticFileHandler, {'path': config.Config().static_path}), + + (r'/', root.RootHandler), + (r'/api/v1/auth/signin', sign.SigninHandler), + (r'/api/v1/auth/signin_return', sign.SigninReturnHandler), + (r'/api/v1/auth/signout', sign.SignoutHandler), + (r'/api/v1/profile', user.ProfileHandler), ] diff --git a/utils/test/testapi/opnfv_testapi/ui/__init__.py b/utils/test/testapi/opnfv_testapi/ui/__init__.py new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/utils/test/testapi/opnfv_testapi/ui/__init__.py diff --git a/utils/test/testapi/opnfv_testapi/ui/auth/__init__.py b/utils/test/testapi/opnfv_testapi/ui/auth/__init__.py new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/utils/test/testapi/opnfv_testapi/ui/auth/__init__.py diff --git a/utils/test/testapi/opnfv_testapi/ui/auth/base.py b/utils/test/testapi/opnfv_testapi/ui/auth/base.py new file mode 100644 index 000000000..bea87c4d9 --- /dev/null +++ b/utils/test/testapi/opnfv_testapi/ui/auth/base.py @@ -0,0 +1,35 @@ +import random +import string + +from six.moves.urllib import parse + +from opnfv_testapi.resources import handlers + + +class BaseHandler(handlers.GenericApiHandler): + def __init__(self, application, request, **kwargs): + super(BaseHandler, self).__init__(application, request, **kwargs) + self.table = 'users' + + def set_cookies(self, cookies): + for cookie_n, cookie_v in cookies: + self.set_secure_cookie(cookie_n, cookie_v) + + +def get_token(length=30): + """Get random token.""" + return ''.join(random.choice(string.ascii_lowercase) + for i in range(length)) + + +def set_query_params(url, params): + """Set params in given query.""" + url_parts = parse.urlparse(url) + url = parse.urlunparse(( + url_parts.scheme, + url_parts.netloc, + url_parts.path, + url_parts.params, + parse.urlencode(params), + url_parts.fragment)) + return url diff --git a/utils/test/testapi/opnfv_testapi/ui/auth/constants.py b/utils/test/testapi/opnfv_testapi/ui/auth/constants.py new file mode 100644 index 000000000..43f69d7f5 --- /dev/null +++ b/utils/test/testapi/opnfv_testapi/ui/auth/constants.py @@ -0,0 +1,16 @@ +OPENID = 'openid' + +# OpenID parameters +OPENID_MODE = 'openid.mode' +OPENID_NS = 'openid.ns' +OPENID_RETURN_TO = 'openid.return_to' +OPENID_CLAIMED_ID = 'openid.claimed_id' +OPENID_IDENTITY = 'openid.identity' +OPENID_REALM = 'openid.realm' +OPENID_NS_SREG = 'openid.ns.sreg' +OPENID_NS_SREG_REQUIRED = 'openid.sreg.required' +OPENID_NS_SREG_EMAIL = 'openid.sreg.email' +OPENID_NS_SREG_FULLNAME = 'openid.sreg.fullname' +OPENID_ERROR = 'openid.error' + +CSRF_TOKEN = 'csrf_token' diff --git a/utils/test/testapi/opnfv_testapi/ui/auth/sign.py b/utils/test/testapi/opnfv_testapi/ui/auth/sign.py new file mode 100644 index 000000000..73190841f --- /dev/null +++ b/utils/test/testapi/opnfv_testapi/ui/auth/sign.py @@ -0,0 +1,57 @@ +from six.moves.urllib import parse + +from opnfv_testapi.common import config +from opnfv_testapi.ui.auth import base +from opnfv_testapi.ui.auth import constants as const + +CONF = config.Config() + + +class SigninHandler(base.BaseHandler): + def get(self): + csrf_token = base.get_token() + return_endpoint = parse.urljoin(CONF.api_url, + CONF.osid_openid_return_to) + return_to = base.set_query_params(return_endpoint, + {const.CSRF_TOKEN: csrf_token}) + + params = { + const.OPENID_MODE: CONF.osid_openid_mode, + const.OPENID_NS: CONF.osid_openid_ns, + const.OPENID_RETURN_TO: return_to, + const.OPENID_CLAIMED_ID: CONF.osid_openid_claimed_id, + const.OPENID_IDENTITY: CONF.osid_openid_identity, + const.OPENID_REALM: CONF.api_url, + const.OPENID_NS_SREG: CONF.osid_openid_ns_sreg, + const.OPENID_NS_SREG_REQUIRED: CONF.osid_openid_sreg_required, + } + url = CONF.osid_openstack_openid_endpoint + url = base.set_query_params(url, params) + self.redirect(url=url, permanent=False) + + +class SigninReturnHandler(base.BaseHandler): + def get(self): + openid = self.get_query_argument(const.OPENID_CLAIMED_ID) + user_info = { + 'openid': openid, + 'email': self.get_query_argument(const.OPENID_NS_SREG_EMAIL), + 'fullname': self.get_query_argument(const.OPENID_NS_SREG_FULLNAME) + } + + self.db_save(self.table, user_info) + if not self.get_secure_cookie('openid'): + self.set_secure_cookie('openid', openid) + self.redirect(url=CONF.ui_url) + + +class SignoutHandler(base.BaseHandler): + def get(self): + """Handle signout request.""" + openid = self.get_secure_cookie(const.OPENID) + if openid: + self.clear_cookie(const.OPENID) + params = {'openid_logout': CONF.osid_openid_logout_endpoint} + url = parse.urljoin(CONF.ui_url, + '/#/logout?' + parse.urlencode(params)) + self.redirect(url) diff --git a/utils/test/testapi/opnfv_testapi/ui/auth/user.py b/utils/test/testapi/opnfv_testapi/ui/auth/user.py new file mode 100644 index 000000000..140bca51c --- /dev/null +++ b/utils/test/testapi/opnfv_testapi/ui/auth/user.py @@ -0,0 +1,24 @@ +from tornado import gen +from tornado import web + +from opnfv_testapi.common import raises +from opnfv_testapi.ui.auth import base + + +class ProfileHandler(base.BaseHandler): + @web.asynchronous + @gen.coroutine + def get(self): + openid = self.get_secure_cookie('openid') + if openid: + try: + user = yield self.db_find_one({'openid': openid}) + self.finish_request({ + "openid": user.get('openid'), + "email": user.get('email'), + "fullname": user.get('fullname'), + "is_admin": False + }) + except Exception: + pass + raises.Unauthorized('Unauthorized') diff --git a/utils/test/testapi/opnfv_testapi/resources/ui_handlers.py b/utils/test/testapi/opnfv_testapi/ui/root.py index 4c14802c4..bba7a8632 100644 --- a/utils/test/testapi/opnfv_testapi/resources/ui_handlers.py +++ b/utils/test/testapi/opnfv_testapi/ui/root.py @@ -2,8 +2,7 @@ from opnfv_testapi.resources.handlers import GenericApiHandler from opnfv_testapi.common import config -class UIHandler(GenericApiHandler): - +class RootHandler(GenericApiHandler): def get_template_path(self): return config.Config().static_path diff --git a/utils/test/testapi/requirements.txt b/utils/test/testapi/requirements.txt index ee144d247..955ffc853 100644 --- a/utils/test/testapi/requirements.txt +++ b/utils/test/testapi/requirements.txt @@ -6,4 +6,5 @@ pbr>=1.6 setuptools>=16.0 tornado>=3.1,<=4.3 epydoc>=0.3.1 +six>=1.9.0 motor |