Commit d86da83c authored by Daniele Venzano's avatar Daniele Venzano

Fix bugs found during manual testing

parent 3127c542
......@@ -41,7 +41,6 @@ class PlainTextAuthenticator:
continue
file_username = row[0]
file_password = row[1]
file_role = row[2]
if file_username == username and file_password == password:
return username, file_role
return True
raise zoe_api.exceptions.ZoeAuthException('Unknown user or password.')
......@@ -48,8 +48,6 @@ class LDAPAuthenticator:
def auth(self, username, password):
"""Authenticate the user or raise an exception."""
search_filter = "uid=" + username
uid = None
role = 'guest'
try:
if self.sasl:
self.connection.sasl_interactive_bind_s('', self.sasl_auth)
......@@ -63,21 +61,9 @@ class LDAPAuthenticator:
result = self.connection.search_s(self.base_dn, ldap.SCOPE_SUBTREE, search_filter)
if len(result) == 0:
raise zoe_api.exceptions.ZoeAuthException('Unknown user or wrong password.')
user_dict = result[0][1]
uid = username
result = self.connection.compare_s(search_filter + ',' + self.base_dn, 'userPassword', password)
if result == 0:
raise zoe_api.exceptions.ZoeAuthException('Unknown user or wrong password.')
gid_numbers = [x.decode('utf-8') for x in user_dict[get_conf().ldap_group_name]]
if get_conf().ldap_admin_gid in gid_numbers:
role = 'admin'
elif get_conf().ldap_user_gid in gid_numbers:
role = 'user'
elif get_conf().ldap_guest_gid in gid_numbers:
role = 'guest'
else:
log.warning('User {} has an unknown group ID ({}), using guest role'.format(username, gid_numbers))
role = 'guest'
except ldap.LDAPError as ex:
if ex.args[0]['desc'] == 'Invalid credentials':
raise zoe_api.exceptions.ZoeAuthException('Unknown user or wrong password.')
......@@ -86,4 +72,4 @@ class LDAPAuthenticator:
zoe_api.exceptions.ZoeAuthException('LDAP error.')
finally:
self.connection.unbind_s()
return uid, role
return True
......@@ -19,6 +19,7 @@ import base64
import logging
import tornado.web
import tornado.websocket
import tornado.escape
from zoe_api.api_endpoint import APIEndpoint # pylint: disable=unused-import
......@@ -63,3 +64,44 @@ class ZoeRequestHandler(tornado.web.RequestHandler):
def data_received(self, chunk):
"""Not implemented as we do not use stream uploads"""
pass
class ZoeWSRequestHandler(tornado.websocket.WebSocketHandler):
"""Customized request handler."""
def initialize(self, **kwargs):
"""Initializes the request handler."""
super().initialize()
self.api_endpoint = kwargs['api_endpoint'] # type: APIEndpoint
def get_current_user(self):
"""Get the user making the request from one of several possible locations."""
auth_header = self.request.headers.get('Authorization')
if self.get_secure_cookie('zoe'): # cookie auth
username = tornado.escape.xhtml_escape(self.get_secure_cookie('zoe'))
user = self.api_endpoint.user_by_name(username)
method = "cookie"
elif auth_header is not None and auth_header.startswith('Basic '): # basic auth
auth_decoded = base64.decodebytes(bytes(auth_header[6:], 'ascii')).decode('utf-8')
username, password = auth_decoded.split(':', 2)
user = BaseAuthenticator().full_auth(username, password)
method = "basic_auth"
else:
method = None
user = None
if user is None:
raise ZoeAuthException('Invalid username or password')
if not user.enabled:
raise ZoeAuthException('User has been disabled by the administrator')
log.debug('Authentication done using {} (user {} from {} for {})'.format(method, user.username, self.request.remote_ip, self.request.path))
return user
def data_received(self, chunk):
"""Not implemented as we do not use stream uploads"""
pass
def on_message(self, message):
"""Must be implemented by a subclass."""
raise NotImplementedError
......@@ -96,9 +96,10 @@ class ExecutionTerminateWeb(ZoeWebRequestHandler):
if self.current_user is None:
return
success, message = self.api_endpoint.execution_terminate(self.current_user, execution_id)
if not success:
self.error_page(error_message=message)
try:
self.api_endpoint.execution_terminate(self.current_user, execution_id)
except zoe_api.exceptions.ZoeException as e:
self.set_status(e.status_code, e.message)
return
self.redirect(self.reverse_url('home_user'))
......@@ -112,7 +113,11 @@ class ExecutionInspectWeb(ZoeWebRequestHandler):
if self.current_user is None:
return
e = self.api_endpoint.execution_by_id(self.current_user, execution_id)
try:
e = self.api_endpoint.execution_by_id(self.current_user, execution_id)
except zoe_api.exceptions.ZoeException as e:
self.set_status(e.status_code, e.message)
return
services_info, endpoints = self.api_endpoint.execution_endpoints(self.current_user, e)
......@@ -142,7 +147,11 @@ class ServiceLogsWeb(ZoeWebRequestHandler):
if self.current_user is None:
return
service = self.api_endpoint.service_by_id(self.current_user, service_id)
try:
service = self.api_endpoint.service_by_id(self.current_user, service_id)
except zoe_api.exceptions.ZoeException as e:
self.set_status(e.status_code, e.message)
return
template_vars = {
"service": service,
......
......@@ -111,9 +111,13 @@ class ZoeWebRequestHandler(ZoeRequestHandler):
'handler': self,
'zoe_version': zoe_lib.version.ZOE_VERSION,
'server_address': self.request.host,
'user': self.current_user
}
try:
ctx['user'] = super().get_current_user()
except ZoeAuthException:
pass
ctx.update(kwargs)
return template.render(ctx)
......
......@@ -60,7 +60,7 @@
{% if endpoints|length > 0 %}
<ul>
{% for endp in endpoints|sort %}
<li><a href="{{ endp[1] }}" target="_blank">{{ endp[0] }}</a></li>
<li><a href="{{ endp[1] }}" target="_blank">{{ endp[0] }}</a> ({{ endp[1] }})</li>
{% endfor %}
</ul>
{% else %}
......
......@@ -64,7 +64,7 @@
{% endfor %}
{% endif %}
<hr>
{% if can_access_api %}
{% if user.role.can_access_api %}
<label class="label-inline"><input type="checkbox" onchange="set_submit_text(this)" name="download_json"> Download JSON with these parameters for command-line execution</label>
<br><br>
{% endif %}
......
......@@ -19,26 +19,24 @@ import json
import logging
from concurrent.futures import ThreadPoolExecutor
import tornado.websocket
import tornado.iostream
import tornado.gen
import zoe_api.exceptions
from zoe_api.api_endpoint import APIEndpoint # pylint: disable=unused-import
from zoe_api.custom_request_handler import ZoeWSRequestHandler
log = logging.getLogger(__name__)
THREAD_POOL = ThreadPoolExecutor(20)
class WebSocketEndpointWeb(tornado.websocket.WebSocketHandler):
class WebSocketEndpointWeb(ZoeWSRequestHandler):
"""Handler class"""
def initialize(self, **kwargs):
"""Initializes the request handler."""
super().initialize()
super().initialize(**kwargs)
self.api_endpoint = kwargs['api_endpoint'] # type: APIEndpoint
self.uid = None
self.role = None
self.connection_closed = None
def open(self, *args, **kwargs):
......
......@@ -74,7 +74,7 @@ def load_configuration(test_conf=None):
argparser.add_argument('--service-logs-base-path', help='Path where service logs coming from the GELF listener will be stored', default='/var/lib/zoe/service-logs')
# API options
argparser.add_argument('--listen-address', type=str, help='Address to listen to for incoming connections', default="0.0.0.0")
argparser.add_argument('--listen-address', help='Address to listen to for incoming connections', default="0.0.0.0")
argparser.add_argument('--listen-port', type=int, help='Port to listen to for incoming connections', default=5001)
argparser.add_argument('--master-url', help='URL of the Zoe master process', default='tcp://127.0.0.1:4850')
argparser.add_argument('--cookie-secret', help='secret used to encrypt cookies', default='changeme')
......@@ -86,6 +86,8 @@ def load_configuration(test_conf=None):
argparser.add_argument('--ldap-bind-password', help='Password for the bind user', default='mysecretpassword')
argparser.add_argument('--ldap-base-dn', help='LDAP base DN for users', default='ou=something,dc=any,dc=local')
argparser.add_argument('--fs-group-id', type=int, help='Group ID to use for all Zoe users in workspace files', default='5001')
# Proxy options
argparser.add_argument('--proxy-path', help='Proxy base path', default='127.0.0.1')
......
......@@ -40,6 +40,7 @@ def gen_environment(execution: Execution, service: Service, env_subst_dict: Dict
env_list.append(('EXECUTION_ID', str(execution.id)))
env_list.append(('DEPLOY_NAME', get_conf().deployment_name))
env_list.append(('UID', execution.owner.fs_uid))
env_list.append(('GID', get_conf().fs_group_id))
env_list.append(('USER', execution.owner.username))
env_list.append(('SERVICE_NAME', service.name))
......
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