From 966d61fda1528834c7ddabf0344e4fcd44a15d4e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adolfo=20G=C3=B3mez=20Garc=C3=ADa?= Date: Fri, 31 Aug 2018 09:15:07 +0200 Subject: [PATCH] Working towards new gui --- server/src/uds/core/auths/auth.py | 47 +--- .../src/uds/core/transports/BaseTransport.py | 4 +- server/src/uds/templatetags/uds.py | 20 +- server/src/uds/urls.py | 4 +- server/src/uds/web/authentication.py | 118 ++++++++++ server/src/uds/web/services.py | 211 ++++++++++++++++++ server/src/uds/web/views/auth.py | 4 +- server/src/uds/web/views/index.py | 175 +-------------- server/src/uds/web/views/modern.py | 26 ++- server/src/uds/web/views/service.py | 9 +- 10 files changed, 393 insertions(+), 225 deletions(-) create mode 100644 server/src/uds/web/authentication.py create mode 100644 server/src/uds/web/services.py diff --git a/server/src/uds/core/auths/auth.py b/server/src/uds/core/auths/auth.py index 9ed7c4603..2f61e3aa5 100644 --- a/server/src/uds/core/auths/auth.py +++ b/server/src/uds/core/auths/auth.py @@ -54,7 +54,7 @@ from uds.models import User import logging import six -__updated__ = '2018-08-02' +__updated__ = '2018-08-31' logger = logging.getLogger(__name__) authLogger = logging.getLogger('authLog') @@ -69,9 +69,7 @@ def getUDSCookie(request, response=None, force=False): Generates a random cookie for uds, used, for example, to encript things ''' if 'uds' not in request.COOKIES: - import random - import string - cookie = ''.join(random.choice(string.letters + string.digits) for _ in range(32)) # @UndefinedVariable + cookie = cryptoManager().randomString(32) if response is not None: response.set_cookie('uds', cookie) request.COOKIES['uds'] = cookie @@ -153,41 +151,16 @@ def trustedSourceRequired(view_func): return _wrapped_view -def getUDSCookie(request, response=None, force=False): - """ - Generates a random cookie for uds, used, for example, to encript things - """ - if 'uds' not in request.COOKIES: - import random - import string - cookie = ''.join(random.choice(string.ascii_letters + string.digits) for _ in range(32)) # @UndefinedVariable - if response is not None: - response.set_cookie('uds', cookie) - request.COOKIES['uds'] = cookie - else: - cookie = request.COOKIES['uds'] +# decorator to deny non authenticated requests +def denyNonAuthenticated(view_func): - if response is not None and force is True: - response.set_cookie('uds', cookie) + @wraps(view_func) + def _wrapped_view(request, *args, **kwargs): + if request.user is None: + return HttpResponseForbidden() + return view_func(request, *args, **kwargs) - return cookie - - -def getRootUser(): - # pylint: disable=unexpected-keyword-arg, no-value-for-parameter - from uds.models import Authenticator - u = User(id=ROOT_ID, name=GlobalConfig.SUPER_USER_LOGIN.get(True), real_name=_('System Administrator'), state=State.ACTIVE, staff_member=True, is_admin=True) - u.manager = Authenticator() - u.getGroups = lambda: [] - u.updateLastAccess = lambda: None - u.logout = lambda: None - return u - - -@deprecated -def getIp(request): - logger.info('Deprecated IP') - return request.ip + return _wrapped_view def __registerUser(authenticator, authInstance, username): diff --git a/server/src/uds/core/transports/BaseTransport.py b/server/src/uds/core/transports/BaseTransport.py index 7bb4bd918..c60b78933 100644 --- a/server/src/uds/core/transports/BaseTransport.py +++ b/server/src/uds/core/transports/BaseTransport.py @@ -38,10 +38,10 @@ from uds.core.util import OsDetector from uds.core import Module from uds.core.transports import protocols from uds.core.util import encoders +from uds.core.util import connection import logging - logger = logging.getLogger(__name__) DIRECT_GROUP = _('Direct') @@ -111,7 +111,7 @@ class Transport(Module): proxy = userService.deployed_service.service.proxy if proxy is not None: return proxy.doTestServer(ip, port, timeout) - return connection.testServer(ip, six.text_type(port), timeout) + return connection.testServer(ip, str(port), timeout) def isAvailableFor(self, userService, ip): """ diff --git a/server/src/uds/templatetags/uds.py b/server/src/uds/templatetags/uds.py index 7a41632aa..f9c9c0cc4 100644 --- a/server/src/uds/templatetags/uds.py +++ b/server/src/uds/templatetags/uds.py @@ -45,6 +45,8 @@ from uds.REST.methods.client import CLIENT_VERSION from uds.core.managers import downloadsManager from uds.core.util.Config import GlobalConfig +from uds.core import VERSION, VERSION_STAMP + from uds.models import Authenticator logger = logging.getLogger(__name__) @@ -92,17 +94,22 @@ def udsJs(context): } config = { + 'version': VERSION, + 'version_stamp': VERSION_STAMP, 'language': get_language(), 'available_languages': [{'id': k, 'name': gettext(v)} for k, v in settings.LANGUAGES], 'authenticators': [getAuth(auth) for auth in authenticators], + 'bypassPluginDetection': False, 'os': request.os['OS'], 'csrf_field': CSRF_FIELD, 'csrf': csrf_token, 'urls': { 'changeLang': reverse('set_language'), - 'login': reverse('uds.web.views.login'), - 'logout': reverse('uds.web.views.logout'), + 'login': reverse('modern.login'), + 'logout': reverse('modern.logout'), 'customAuth': reverse('uds.web.views.customAuth', kwargs={'idAuth': ''}), + 'services': reverse('modern.services'), + 'enabler': reverse('ClientAccessEnabler', kwargs={ 'idService': 'param1', 'idTransport': 'param2' }), } } @@ -121,17 +128,22 @@ def udsJs(context): ) ] - actors = []; + actors = [] if profile['role'] == 'staff': # Add staff things actors = [{'url': reverse('uds.web.views.download', kwargs={'idDownload': key}), 'name': val['name'], 'description': gettext(val['comment'])} for key, val in downloadsManager().getDownloadables().items()] config['urls']['admin'] = reverse('uds.admin.views.index') + if request.user: + prefs = request.user.prefs('_uds') + # Update bypass configuration with user information + config['bypassPluginDetection'] = prefs.get('bypassPluginDetection') == '1' + uds = { 'profile': profile, 'config': config, 'plugins': plugins, - 'actors': actors + 'actors': actors, } javascript = 'var udsData = ' + json.dumps(uds) + ';\n'; diff --git a/server/src/uds/urls.py b/server/src/uds/urls.py index c1d635fa6..020894b73 100644 --- a/server/src/uds/urls.py +++ b/server/src/uds/urls.py @@ -96,7 +96,9 @@ urlpatterns = [ # Modern path('js', uds.web.views.modern.js, name="uds.js"), - path(r'modern/login/', uds.web.views.login, name='modern.login'), + path(r'modern/login/', uds.web.views.modern.login, name='modern.login'), + path(r'modern/logout/', uds.web.views.logout, name='modern.logout'), + path(r'modern/services/', uds.web.views.modern.services, name='modern.services'), re_path('^modern.*', uds.web.views.modern.index, name='modern.index'), ] diff --git a/server/src/uds/web/authentication.py b/server/src/uds/web/authentication.py new file mode 100644 index 000000000..d734df941 --- /dev/null +++ b/server/src/uds/web/authentication.py @@ -0,0 +1,118 @@ +# -*- coding: utf-8 -*- +# +# Copyright (c) 2018 Virtual Cable S.L. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without modification, +# are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, +# this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# * Neither the name of Virtual Cable S.L. nor the names of its contributors +# may be used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +""" +@author: Adolfo Gómez, dkmaster at dkmon dot com +""" + +from django.utils.translation import ugettext as _ + +from uds.core.auths.auth import authenticate, authLogLogin +from uds.models import Authenticator +from uds.core.util.Config import GlobalConfig +from uds.core.util.Cache import Cache +from uds.core.util.model import processUuid + +import uds.web.errors as errors +import logging + +logger = logging.getLogger(__name__) + + +# Returns: +# (None, ErroString) if error +# (None, NumericError) if errorview redirection +# (User, password_string) if all if fine +def checkLogin(request, form, tag=None): + host = request.META.get('HTTP_HOST') or request.META.get('SERVER_NAME') or 'auth_host' # Last one is a placeholder in case we can't locate host name + + # Get Authenticators limitation + logger.debug('Host: {0}'.format(host)) + if GlobalConfig.DISALLOW_GLOBAL_LOGIN.getBool(False) is True: + if tag is None: + try: + Authenticator.objects.get(small_name=host) + tag = host + except Exception: + try: + tag = Authenticator.objects.order_by('priority')[0].small_name + except Exception: # There is no authenticators yet, simply allow global login to nowhere.. :-) + tag = None + + logger.debug('Tag: {0}'.format(tag)) + + if 'uds' not in request.COOKIES: + logger.debug('Request does not have uds cookie') + return (None, errors.COOKIES_NEEDED) + if form.is_valid(): + os = request.os + try: + authenticator = Authenticator.objects.get(uuid=processUuid(form.cleaned_data['authenticator'])) + except Exception: + authenticator = Authenticator() + userName = form.cleaned_data['user'] + if GlobalConfig.LOWERCASE_USERNAME.getBool(True) is True: + userName = userName.lower() + + cache = Cache('auth') + cacheKey = str(authenticator.id) + userName + tries = cache.get(cacheKey) + if tries is None: + tries = 0 + if authenticator.getInstance().blockUserOnLoginFailures is True and tries >= GlobalConfig.MAX_LOGIN_TRIES.getInt(): + authLogLogin(request, authenticator, userName, 'Temporarily blocked') + return (None, _('Too many authentication errrors. User temporarily blocked')) + else: + password = form.cleaned_data['password'] + user = None + if password == '': + password = 'axd56adhg466jasd6q8sadñ€sáé--v' # Random string, in fact, just a placeholder that will not be used :) + user = authenticate(userName, password, authenticator) + logger.debug('User: {}'.format(user)) + + if user is None: + logger.debug("Invalid user {0} (access denied)".format(userName)) + tries += 1 + cache.put(cacheKey, tries, GlobalConfig.LOGIN_BLOCK.getInt()) + authLogLogin(request, authenticator, userName, 'Access denied (user not allowed by UDS)') + return (None, _('Access denied')) + else: + request.session.cycle_key() + + logger.debug('User {} has logged in'.format(userName)) + cache.remove(cacheKey) # Valid login, remove cached tries + + # Add the "java supported" flag to session + request.session['OS'] = os + if form.cleaned_data['logouturl'] != '': + logger.debug('The logoout url will be {}'.format(form.cleaned_data['logouturl'])) + request.session['logouturl'] = form.cleaned_data['logouturl'] + authLogLogin(request, authenticator, user.name) + return (user, form.cleaned_data['password']) + + logger.info('Invalid form received') + return (None, _('Invalid data')) diff --git a/server/src/uds/web/services.py b/server/src/uds/web/services.py new file mode 100644 index 000000000..429e1c95f --- /dev/null +++ b/server/src/uds/web/services.py @@ -0,0 +1,211 @@ +# -*- coding: utf-8 -*- +# +# Copyright (c) 2012 Virtual Cable S.L. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without modification, +# are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, +# this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# * Neither the name of Virtual Cable S.L. nor the names of its contributors +# may be used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +""" +@author: Adolfo Gómez, dkmaster at dkmon dot com +""" +from __future__ import unicode_literals + +from django.urls import reverse +from django.utils.translation import ugettext +from django.utils import formats + +from uds.models import DeployedService, Transport, UserService, Network, ServicesPoolGroup +from uds.core.util.Config import GlobalConfig +from uds.core.util import html + +from uds.core.managers.UserServiceManager import UserServiceManager + +import logging + +logger = logging.getLogger(__name__) + + +def getServicesData(request): + # Session data + os = request.os + + # We look for services for this authenticator groups. User is logged in in just 1 authenticator, so his groups must coincide with those assigned to ds + groups = list(request.user.getGroups()) + availServices = DeployedService.getDeployedServicesForGroups(groups) + availUserServices = UserService.getUserAssignedServices(request.user) + + # Information for administrators + nets = '' + validTrans = '' + + logger.debug('OS: {0}'.format(os['OS'])) + + if request.user.isStaff(): + nets = ','.join([n.name for n in Network.networksFor(request.ip)]) + tt = [] + for t in Transport.objects.all(): + if t.validForIp(request.ip): + tt.append(t.name) + validTrans = ','.join(tt) + + # Extract required data to show to user + services = [] + # Select assigned user services (manually assigned) + for svr in availUserServices: + trans = [] + for t in svr.transports.all().order_by('priority'): + typeTrans = t.getType() + if t.validForIp(request.ip) and typeTrans.supportsOs(os['OS']) and t.validForOs(os['OS']): + if typeTrans.ownLink is True: + link = reverse('TransportOwnLink', args=('A' + svr.uuid, t.uuid)) + else: + link = html.udsAccessLink(request, 'A' + svr.uuid, t.uuid) + trans.append( + { + 'id': t.uuid, + 'name': t.name, + 'link': link + } + ) + + servicePool = svr.deployed_service + + if servicePool.image is not None: + imageId = servicePool.image.uuid + else: + imageId = 'x' # Invalid + + # Extract app group + group = servicePool.servicesPoolGroup if servicePool.servicesPoolGroup is not None else ServicesPoolGroup.default().as_dict + + services.append({ + 'id': 'A' + svr.uuid, + 'name': servicePool.name, + 'visual_name': servicePool.visual_name, + 'description': servicePool.comments, + 'group': group, + 'transports': trans, + 'imageId': imageId, + 'show_transports': servicePool.show_transports, + 'allow_users_remove': servicePool.allow_users_remove, + 'allow_users_reset': servicePool.allow_users_reset, + 'maintenance': servicePool.isInMaintenance(), + 'not_accesible': not servicePool.isAccessAllowed(), + 'in_use': svr.in_use, + 'to_be_replaced': False, # Manually assigned will not be autoremoved never + 'comments': servicePool.comments, + }) + + logger.debug(services) + + # Now generic user service + for svr in availServices: + trans = [] + for t in svr.transports.all().order_by('priority'): + typeTrans = t.getType() + if typeTrans is None: # This may happen if we "remove" a transport type but we have a transport of that kind on DB + continue + if t.validForIp(request.ip) and typeTrans.supportsOs(os['OS']) and t.validForOs(os['OS']): + if typeTrans.ownLink is True: + link = reverse('TransportOwnLink', args=('F' + svr.uuid, t.uuid)) + else: + link = html.udsAccessLink(request, 'F' + svr.uuid, t.uuid) + trans.append( + { + 'id': t.uuid, + 'name': t.name, + 'link': link, + 'priority': t.priority + } + ) + if svr.image is not None: + imageId = svr.image.uuid + else: + imageId = 'x' + + # Locate if user service has any already assigned user service for this + ads = UserServiceManager.manager().getExistingAssignationForUser(svr, request.user) + if ads is None: + in_use = False + else: + in_use = ads.in_use + + group = svr.servicesPoolGroup.as_dict if svr.servicesPoolGroup is not None else ServicesPoolGroup.default().as_dict + + tbr = svr.toBeReplaced() + if tbr is not None: + tbr = formats.date_format(tbr, "SHORT_DATETIME_FORMAT") + tbrt = ugettext('This service is about to be replaced by a new version. Please, close the session before {} and save all your work to avoid loosing it.').format(tbr) + else: + tbrt = '' + + services.append({ + 'id': 'F' + svr.uuid, + 'name': svr.name, + 'visual_name': svr.visual_name, + 'description': svr.comments, + 'group': group, + 'transports': trans, + 'imageId': imageId, + 'show_transports': svr.show_transports, + 'allow_users_remove': svr.allow_users_remove, + 'allow_users_reset': svr.allow_users_reset, + 'maintenance': svr.isInMaintenance(), + 'not_accesible': not svr.isAccessAllowed(), + 'in_use': in_use, + 'to_be_replaced': tbr, + 'to_be_replaced_text': tbrt, + 'comments': svr.comments, + }) + + logger.debug('Services: {0}'.format(services)) + + services = sorted(services, key=lambda s: s['name'].upper()) + + autorun = False + if len(services) == 1 and GlobalConfig.AUTORUN_SERVICE.getBool(True) and len(services[0]['transports']) > 0: + if request.session.get('autorunDone', '0') == '0': + request.session['autorunDone'] = '1' + autorun = True + # return redirect('uds.web.views.service', idService=services[0]['id'], idTransport=services[0]['transports'][0]['id']) + + # List of services groups + allGroups = [v for v in sorted([ser['group'] for ser in services], key=lambda s: s['priority'])] + # Now remove duplicates + groups = [] + already = [] + for g in allGroups: + if g['name'] not in already: + already.append(g['name']) + groups.append(g) + + logger.debug('Groups: {}'.format(groups)) + + return { + 'groups': groups, + 'services': services, + 'ip': request.ip, + 'nets': nets, + 'transports': validTrans, + 'autorun': autorun + } diff --git a/server/src/uds/web/views/auth.py b/server/src/uds/web/views/auth.py index e262e86d0..017cb8c5b 100644 --- a/server/src/uds/web/views/auth.py +++ b/server/src/uds/web/views/auth.py @@ -42,7 +42,7 @@ from django.views.decorators.csrf import csrf_exempt import uds.web.errors as errors from uds.core.auths.Exceptions import InvalidUserException from uds.core.auths.auth import webLogin, webLogout, authenticateViaCallback, authLogLogin, getUDSCookie -from uds.core.managers import userServiceManager +from uds.core.managers import userServiceManager, cryptoManager from uds.core.services.Exceptions import InvalidServiceException, ServiceNotReadyError from uds.core.ui import theme from uds.core.util import OsDetector @@ -53,7 +53,7 @@ from uds.models import TicketStore logger = logging.getLogger(__name__) -__updated__ = '2018-06-27' +__updated__ = '2018-08-31' @csrf_exempt diff --git a/server/src/uds/web/views/index.py b/server/src/uds/web/views/index.py index 872118f49..6ca80a0c4 100644 --- a/server/src/uds/web/views/index.py +++ b/server/src/uds/web/views/index.py @@ -31,25 +31,19 @@ from __future__ import unicode_literals from django.shortcuts import render -from django.urls import reverse -from django.utils.translation import ugettext -from django.utils import formats from uds.core.auths.auth import webLoginRequired, webLogout -from uds.models import DeployedService, Transport, UserService, Network, ServicesPoolGroup -from uds.core.util.Config import GlobalConfig -from uds.core.util import html - from uds.core.ui import theme -from uds.core.managers.UserServiceManager import UserServiceManager from uds.core import VERSION, VERSION_STAMP +from uds.web.services import getServicesData + import logging logger = logging.getLogger(__name__) -__updated__ = '2018-03-14' +__updated__ = '2018-08-31' def about(request): @@ -75,170 +69,11 @@ def index(request): if request.session.get('ticket') == '1': return webLogout(request) - # Session data - os = request.os - - # We look for services for this authenticator groups. User is logged in in just 1 authenticator, so his groups must coincide with those assigned to ds - groups = list(request.user.getGroups()) - availServices = DeployedService.getDeployedServicesForGroups(groups) - availUserServices = UserService.getUserAssignedServices(request.user) - - # Information for administrators - nets = '' - validTrans = '' - - logger.debug('OS: {0}'.format(os['OS'])) - - if request.user.isStaff(): - nets = ','.join([n.name for n in Network.networksFor(request.ip)]) - tt = [] - for t in Transport.objects.all(): - if t.validForIp(request.ip): - tt.append(t.name) - validTrans = ','.join(tt) - - # Extract required data to show to user - services = [] - # Select assigned user services (manually assigned) - for svr in availUserServices: - trans = [] - for t in svr.transports.all().order_by('priority'): - typeTrans = t.getType() - if t.validForIp(request.ip) and typeTrans.supportsOs(os['OS']) and t.validForOs(os['OS']): - if typeTrans.ownLink is True: - link = reverse('TransportOwnLink', args=('A' + svr.uuid, t.uuid)) - else: - link = html.udsAccessLink(request, 'A' + svr.uuid, t.uuid) - trans.append( - { - 'id': t.uuid, - 'name': t.name, - 'link': link - } - ) - - servicePool = svr.deployed_service - - if servicePool.image is not None: - imageId = servicePool.image.uuid - else: - imageId = 'x' # Invalid - - # Extract app group - group = servicePool.servicesPoolGroup if servicePool.servicesPoolGroup is not None else ServicesPoolGroup.default().as_dict - - services.append({ - 'id': 'A' + svr.uuid, - 'name': servicePool.name, - 'visual_name': servicePool.visual_name, - 'description': servicePool.comments, - 'group': group, - 'transports': trans, - 'imageId': imageId, - 'show_transports': servicePool.show_transports, - 'allow_users_remove': servicePool.allow_users_remove, - 'allow_users_reset': servicePool.allow_users_reset, - 'maintenance': servicePool.isInMaintenance(), - 'not_accesible': not servicePool.isAccessAllowed(), - 'in_use': svr.in_use, - 'to_be_replaced': False, # Manually assigned will not be autoremoved never - 'comments': servicePool.comments, - }) - - logger.debug(services) - - # Now generic user service - for svr in availServices: - trans = [] - for t in svr.transports.all().order_by('priority'): - typeTrans = t.getType() - if typeTrans is None: # This may happen if we "remove" a transport type but we have a transport of that kind on DB - continue - if t.validForIp(request.ip) and typeTrans.supportsOs(os['OS']) and t.validForOs(os['OS']): - if typeTrans.ownLink is True: - link = reverse('TransportOwnLink', args=('F' + svr.uuid, t.uuid)) - else: - link = html.udsAccessLink(request, 'F' + svr.uuid, t.uuid) - trans.append( - { - 'id': t.uuid, - 'name': t.name, - 'link': link - } - ) - if svr.image is not None: - imageId = svr.image.uuid - else: - imageId = 'x' - - # Locate if user service has any already assigned user service for this - ads = UserServiceManager.manager().getExistingAssignationForUser(svr, request.user) - if ads is None: - in_use = False - else: - in_use = ads.in_use - - group = svr.servicesPoolGroup.as_dict if svr.servicesPoolGroup is not None else ServicesPoolGroup.default().as_dict - - tbr = svr.toBeReplaced() - if tbr is not None: - tbr = formats.date_format(tbr, "SHORT_DATETIME_FORMAT") - tbrt = ugettext('This service is about to be replaced by a new version. Please, close the session before {} and save all your work to avoid loosing it.').format(tbr) - else: - tbrt = '' - - services.append({ - 'id': 'F' + svr.uuid, - 'name': svr.name, - 'visual_name': svr.visual_name, - 'description': svr.comments, - 'group': group, - 'transports': trans, - 'imageId': imageId, - 'show_transports': svr.show_transports, - 'allow_users_remove': svr.allow_users_remove, - 'allow_users_reset': svr.allow_users_reset, - 'maintenance': svr.isInMaintenance(), - 'not_accesible': not svr.isAccessAllowed(), - 'in_use': in_use, - 'to_be_replaced': tbr, - 'to_be_replaced_text': tbrt, - 'comments': svr.comments, - }) - - logger.debug('Services: {0}'.format(services)) - - services = sorted(services, key=lambda s: s['name'].upper()) - - autorun = False - if len(services) == 1 and GlobalConfig.AUTORUN_SERVICE.getBool(True) and len(services[0]['transports']) > 0: - if request.session.get('autorunDone', '0') == '0': - request.session['autorunDone'] = '1' - autorun = True - # return redirect('uds.web.views.service', idService=services[0]['id'], idTransport=services[0]['transports'][0]['id']) - - # List of services groups - allGroups = [v for v in sorted([ser['group'] for ser in services], key=lambda s: s['priority'])] - # Now remove duplicates - groups = [] - already = [] - for g in allGroups: - if g['name'] not in already: - already.append(g['name']) - groups.append(g) - - logger.debug('Groups: {}'.format(groups)) + data = getServicesData(request) response = render( request, theme.template('index.html'), - { - 'groups': groups, - 'services': services, - 'ip': request.ip, - 'nets': nets, - 'transports': validTrans, - 'autorun': autorun - } + data ) return response diff --git a/server/src/uds/web/views/modern.py b/server/src/uds/web/views/modern.py index bfbb4dbc7..e8bc47a37 100644 --- a/server/src/uds/web/views/modern.py +++ b/server/src/uds/web/views/modern.py @@ -29,17 +29,25 @@ @author: Adolfo Gómez, dkmaster at dkmon dot com """ import logging +import json from django.shortcuts import render -from uds.core.auths.auth import getUDSCookie +from django.http import HttpResponse +from django.urls import reverse +from uds.core.auths.auth import ( + getUDSCookie, + denyNonAuthenticated +) +from uds.web.services import getServicesData logger = logging.getLogger(__name__) def index(request): - response = render(request, 'uds/modern/index.html', {}) + logger.debug('Session expires at %s', request.session.get_expiry_date()) + # Ensure UDS cookie is present getUDSCookie(request, response) @@ -52,7 +60,6 @@ def login(request, tag=None): from uds.web.authentication import checkLogin from uds.core.auths.auth import webLogin from django.http import HttpResponseRedirect - from django.urls import reverse # Default empty form if request.method == 'POST': @@ -65,9 +72,20 @@ def login(request, tag=None): # If error is numeric, redirect... # Error, set error on session for process for js request.session['errors'] = data + return HttpResponse(data); else: - return index(request) + response = index(request) + + return response def js(request): return render(request, 'uds/js.js', content_type='text/javascript') + + +@denyNonAuthenticated +def services(request): + data = getServicesData(request) + + return HttpResponse(content=json.dumps(data), content_type='application/json') + diff --git a/server/src/uds/web/views/service.py b/server/src/uds/web/views/service.py index 8d217777b..c17e061d7 100644 --- a/server/src/uds/web/views/service.py +++ b/server/src/uds/web/views/service.py @@ -48,13 +48,12 @@ from uds.core.services.Exceptions import ServiceNotReadyError, MaxServicesReache import uds.web.errors as errors -import six import json import logging logger = logging.getLogger(__name__) -__updated__ = '2018-08-02' +__updated__ = '2018-08-31' @webLoginRequired(admin=False) @@ -140,12 +139,12 @@ def clientEnabler(request, idService, idTransport): error = errors.errorString(errors.SERVICE_CALENDAR_DENIED) except Exception as e: logger.exception('Error') - error = six.text_type(e) + error = str(e) return HttpResponse( json.dumps({ - 'url': six.text_type(url), - 'error': six.text_type(error) + 'url': str(url), + 'error': str(error) }), content_type='application/json' )