Commit e331f298 authored by Daniele Venzano's avatar Daniele Venzano

CORS headers and additional login options for the API

Merge from Quang-Nhat Hoang-Xuan private tree
parent beeb3905
......@@ -21,9 +21,11 @@ import tornado.web
from zoe_api.rest_api.execution import ExecutionAPI, ExecutionCollectionAPI, ExecutionDeleteAPI
from zoe_api.rest_api.info import InfoAPI
from zoe_api.rest_api.userinfo import UserInfoAPI
from zoe_api.rest_api.service import ServiceAPI
from zoe_api.rest_api.discovery import DiscoveryAPI
from zoe_api.rest_api.statistics import SchedulerStatsAPI
from zoe_api.rest_api.login import LoginAPI
from zoe_lib.version import ZOE_API_VERSION
......@@ -38,6 +40,8 @@ def api_init(api_endpoint) -> List[tornado.web.URLSpec]:
api_routes = [
tornado.web.url(API_PATH + r'/info', InfoAPI, route_args),
tornado.web.url(API_PATH + r'/login', LoginAPI, route_args),
tornado.web.url(API_PATH + r'/userinfo', UserInfoAPI, route_args),
tornado.web.url(API_PATH + r'/execution/([0-9]+)', ExecutionAPI, route_args),
tornado.web.url(API_PATH + r'/execution/delete/([0-9]+)', ExecutionDeleteAPI, route_args),
......
......@@ -18,7 +18,7 @@
from tornado.web import RequestHandler
from zoe_api.api_endpoint import APIEndpoint # pylint: disable=unused-import
from zoe_api.rest_api.utils import catch_exceptions
from zoe_api.rest_api.utils import catch_exceptions, manage_cors_headers
class DiscoveryAPI(RequestHandler):
......@@ -28,6 +28,15 @@ class DiscoveryAPI(RequestHandler):
"""Initializes the request handler."""
self.api_endpoint = kwargs['api_endpoint'] # type: APIEndpoint
def set_default_headers(self):
"""Set up the headers for enabling CORS."""
manage_cors_headers(self)
def options(self):
"""Needed for CORS."""
self.set_status(204)
self.finish()
@catch_exceptions
def get(self, execution_id: int, service_group: str):
"""HTTP GET method."""
......
......@@ -18,7 +18,7 @@
from tornado.web import RequestHandler
import tornado.escape
from zoe_api.rest_api.utils import catch_exceptions, get_auth
from zoe_api.rest_api.utils import catch_exceptions, get_auth, manage_cors_headers
import zoe_api.exceptions
from zoe_api.api_endpoint import APIEndpoint # pylint: disable=unused-import
......@@ -30,6 +30,15 @@ class ExecutionAPI(RequestHandler):
"""Initializes the request handler."""
self.api_endpoint = kwargs['api_endpoint'] # type: APIEndpoint
def set_default_headers(self):
"""Set up the headers for enabling CORS."""
manage_cors_headers(self)
def options(self, execution_id):
"""Needed for CORS."""
self.set_status(204)
self.finish()
@catch_exceptions
def get(self, execution_id):
"""GET a single execution by its ID."""
......
......@@ -17,7 +17,7 @@
from tornado.web import RequestHandler
from zoe_api.rest_api.utils import catch_exceptions
from zoe_api.rest_api.utils import catch_exceptions, manage_cors_headers
from zoe_api.api_endpoint import APIEndpoint # pylint: disable=unused-import
from zoe_lib.config import get_conf
......@@ -31,6 +31,15 @@ class InfoAPI(RequestHandler):
"""Initializes the request handler."""
self.api_endpoint = kwargs['api_endpoint'] # type: APIEndpoint
def set_default_headers(self):
"""Set up the headers for enabling CORS."""
manage_cors_headers(self)
def options(self):
"""Needed for CORS."""
self.set_status(204)
self.finish()
@catch_exceptions
def get(self):
"""HTTP GET method."""
......
# Copyright (c) 2016, Quang-Nhat Hoang-Xuan
#
# 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.
"""The Info API endpoint."""
from tornado.web import RequestHandler
from zoe_api.rest_api.utils import get_auth, catch_exceptions, manage_cors_headers
from zoe_api.api_endpoint import APIEndpoint # pylint: disable=unused-import
class LoginAPI(RequestHandler):
"""The Login API endpoint."""
def initialize(self, **kwargs):
"""Initializes the request handler."""
self.api_endpoint = kwargs['api_endpoint'] # type: APIEndpoint
def set_default_headers(self):
"""Set up the headers for enabling CORS."""
manage_cors_headers(self)
@catch_exceptions
def options(self):
"""Needed for CORS."""
self.set_status(204)
self.finish()
@catch_exceptions
def get(self):
"""HTTP GET method."""
uid, role = get_auth(self)
cookie_val = uid + '.' + role
self.set_secure_cookie('zoe', cookie_val)
ret = {
'uid': uid,
'role': role
}
self.write(ret)
def data_received(self, chunk):
"""Not implemented as we do not use stream uploads"""
pass
......@@ -20,7 +20,7 @@ import logging
from tornado.web import RequestHandler
from zoe_api.rest_api.utils import catch_exceptions, get_auth
from zoe_api.rest_api.utils import catch_exceptions, get_auth, manage_cors_headers
from zoe_api.api_endpoint import APIEndpoint # pylint: disable=unused-import
log = logging.getLogger(__name__)
......@@ -35,6 +35,16 @@ class ServiceAPI(RequestHandler):
"""Initializes the request handler."""
self.api_endpoint = kwargs['api_endpoint'] # type: APIEndpoint
def set_default_headers(self):
"""Set up the headers for enabling CORS."""
manage_cors_headers(self)
@catch_exceptions
def options(self, service_id):
"""Needed for CORS."""
self.set_status(204)
self.finish()
@catch_exceptions
def get(self, service_id):
"""HTTP GET method."""
......
......@@ -18,7 +18,7 @@
from tornado.web import RequestHandler
from zoe_api.api_endpoint import APIEndpoint # pylint: disable=unused-import
from zoe_api.rest_api.utils import catch_exceptions
from zoe_api.rest_api.utils import catch_exceptions, manage_cors_headers
class SchedulerStatsAPI(RequestHandler):
......@@ -28,6 +28,16 @@ class SchedulerStatsAPI(RequestHandler):
"""Initializes the request handler."""
self.api_endpoint = kwargs['api_endpoint'] # type: APIEndpoint
def set_default_headers(self):
"""Set up the headers for enabling CORS."""
manage_cors_headers(self)
@catch_exceptions
def options(self):
"""Needed for CORS."""
self.set_status(204)
self.finish()
@catch_exceptions
def get(self):
"""HTTP GET method."""
......
# Copyright (c) 2016, Quang-Nhat Hoang-Xuan
#
# 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.
"""The Info API endpoint."""
from tornado.web import RequestHandler
from zoe_api.rest_api.utils import get_auth, catch_exceptions, manage_cors_headers
from zoe_api.api_endpoint import APIEndpoint # pylint: disable=unused-import
class UserInfoAPI(RequestHandler):
"""The UserInfo API endpoint."""
def initialize(self, **kwargs):
"""Initializes the request handler."""
self.api_endpoint = kwargs['api_endpoint'] # type: APIEndpoint
def set_default_headers(self):
"""Set up the headers for enabling CORS."""
manage_cors_headers(self)
@catch_exceptions
def options(self):
"""Needed for CORS."""
self.set_status(204)
self.finish()
@catch_exceptions
def get(self):
"""HTTP GET method."""
uid, role = get_auth(self)
ret = {
'uid': uid,
'role': role
}
self.write(ret)
def data_received(self, chunk):
"""Not implemented as we do not use stream uploads"""
pass
......@@ -26,6 +26,7 @@ from zoe_lib.config import get_conf
from zoe_api.exceptions import ZoeRestAPIException, ZoeNotFoundException, ZoeAuthException, ZoeException
from zoe_api.auth.ldap import LDAPAuthenticator
from zoe_api.auth.file import PlainTextAuthenticator
from zoe_api.auth.ldapsasl import LDAPSASLAuthenticator
from zoe_api.auth.base import BaseAuthenticator # pylint: disable=unused-import
......@@ -68,6 +69,12 @@ def catch_exceptions(func):
def get_auth(handler: tornado.web.RequestHandler):
"""Try to authenticate a request."""
if handler.get_secure_cookie('zoe'):
cookie_val = str(handler.get_secure_cookie('zoe'))
uid, role = cookie_val[2:-1].split('.')
log.info('Authentication done using cookie')
return uid, role
auth_header = handler.request.headers.get('Authorization')
if auth_header is None or not auth_header.startswith('Basic '):
raise ZoeRestAPIException('missing or wrong authentication information', 401, {'WWW-Authenticate': 'Basic realm="Login Required"'})
......@@ -79,10 +86,25 @@ def get_auth(handler: tornado.web.RequestHandler):
authenticator = PlainTextAuthenticator() # type: BaseAuthenticator
elif get_conf().auth_type == 'ldap':
authenticator = LDAPAuthenticator()
elif get_conf().auth_type == 'ldapsasl':
authenticator = LDAPSASLAuthenticator()
else:
raise ZoeException('Configuration error, unknown authentication method: {}'.format(get_conf().auth_type))
uid, role = authenticator.auth(username, password)
if uid is None:
raise ZoeRestAPIException('missing or wrong authentication information', 401, {'WWW-Authenticate': 'Basic realm="Login Required"'})
log.debug('Authentication done using auth-mechanism')
return uid, role
def manage_cors_headers(handler: tornado.web.RequestHandler):
"""Set up the headers for enabling CORS."""
if handler.request.headers.get('Origin') is None:
handler.set_header("Access-Control-Allow-Origin", "*")
else:
handler.set_header("Access-Control-Allow-Origin", handler.request.headers.get('Origin'))
handler.set_header("Access-Control-Allow-Credentials", "true")
handler.set_header("Access-Control-Allow-Headers", "x-requested-with, Content-Type, origin, authorization, accept, client-security-token")
handler.set_header("Access-Control-Allow-Methods", "OPTIONS, GET, DELETE")
handler.set_header("Access-Control-Max-Age", "1000")
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment