diff --git a/server/src/uds/core/managers/UserServiceManager.py b/server/src/uds/core/managers/UserServiceManager.py index a7ec0ca58..cf0b7478c 100644 --- a/server/src/uds/core/managers/UserServiceManager.py +++ b/server/src/uds/core/managers/UserServiceManager.py @@ -51,6 +51,8 @@ import requests import json import logging +__updated__ = '2015-05-06' + logger = logging.getLogger(__name__) USERSERVICE_TAG = 'cm-' diff --git a/server/src/uds/core/transports/BaseTransport.py b/server/src/uds/core/transports/BaseTransport.py index 2e799a3c2..b4024351e 100644 --- a/server/src/uds/core/transports/BaseTransport.py +++ b/server/src/uds/core/transports/BaseTransport.py @@ -40,6 +40,8 @@ from uds.core.transports import protocols import logging +__updated__ = '2015-05-06' + logger = logging.getLogger(__name__) diff --git a/server/src/uds/services/OVirt/OVirtLinkedDeployment.py b/server/src/uds/services/OVirt/OVirtLinkedDeployment.py index da7890eb1..e9cf87fb5 100644 --- a/server/src/uds/services/OVirt/OVirtLinkedDeployment.py +++ b/server/src/uds/services/OVirt/OVirtLinkedDeployment.py @@ -30,7 +30,6 @@ ''' .. moduleauthor:: Adolfo Gómez, dkmaster at dkmon dot com ''' - from uds.core.services import UserDeployment from uds.core.util.State import State from uds.core.util import log @@ -38,6 +37,9 @@ from uds.core.util import log import cPickle import logging +__updated__ = '2015-05-09' + + logger = logging.getLogger(__name__) opCreate, opStart, opStop, opSuspend, opRemove, opWait, opError, opFinish, opRetry, opChangeMac = range(10) @@ -181,6 +183,12 @@ class OVirtLinkedDeployment(UserDeployment): self.cache().put('ready', '1') return State.FINISHED + def getConsoleConnection(self): + return self.service().getConsoleConnection(self._vmid) + + def desktopLogin(self, username, password, domain=''): + return self.service().desktopLogin(self._vmId, username, password, domain) + def notifyReadyFromOsManager(self, data): # Here we will check for suspending the VM (when full ready) logger.debug('Checking if cache 2 for {0}'.format(self._name)) diff --git a/server/src/uds/services/OVirt/OVirtLinkedService.py b/server/src/uds/services/OVirt/OVirtLinkedService.py index 3b21af8c0..ddcd66317 100644 --- a/server/src/uds/services/OVirt/OVirtLinkedService.py +++ b/server/src/uds/services/OVirt/OVirtLinkedService.py @@ -30,7 +30,6 @@ ''' .. moduleauthor:: Adolfo Gómez, dkmaster at dkmon dot com ''' - from django.utils.translation import ugettext_noop as _, ugettext from uds.core.services import Service from .OVirtPublication import OVirtPublication @@ -41,6 +40,8 @@ from uds.core.ui import gui import logging +__updated__ = '2015-05-09' + logger = logging.getLogger(__name__) @@ -104,29 +105,71 @@ class OVirtLinkedService(Service): tooltip=_("Cluster to contain services"), required=True ) - datastore = gui.ChoiceField(label=_("Datastore Domain"), rdonly=False, order=3, - tooltip=_('Datastore domain where to publish and put incrementals'), required=True) + datastore = gui.ChoiceField( + label=_("Datastore Domain"), + rdonly=False, + order=3, + tooltip=_('Datastore domain where to publish and put incrementals'), + required=True + ) - minSpaceGB = gui.NumericField(length=3, label=_('Reserved Space'), defvalue='32', order=4, tooltip=_('Minimal free space in GB'), required=True) + minSpaceGB = gui.NumericField( + length=3, + label=_('Reserved Space'), + defvalue='32', + order=4, + tooltip=_('Minimal free space in GB'), + required=True + ) - memory = gui.NumericField(label=_("Memory (Mb)"), length=4, defvalue=512, rdonly=False, order=5, - tooltip=_('Memory assigned to machines'), required=True) + memory = gui.NumericField( + label=_("Memory (Mb)"), + length=4, + defvalue=512, + rdonly=False, + order=5, + tooltip=_('Memory assigned to machines'), + required=True + ) - memoryGuaranteed = gui.NumericField(label=_("Memory Guaranteed (Mb)"), length=4, defvalue=256, rdonly=False, order=6, - tooltip=_('Physical memory guaranteed to machines'), required=True) + memoryGuaranteed = gui.NumericField( + label=_("Memory Guaranteed (Mb)"), + length=4, + defvalue=256, + rdonly=False, + order=6, + tooltip=_('Physical memory guaranteed to machines'), + required=True + ) - baseName = gui.TextField(label=_('Machine Names'), rdonly=False, order=6, tooltip=('Base name for clones from this machine'), required=True) + baseName = gui.TextField( + label=_('Machine Names'), + rdonly=False, + order=6, + tooltip=('Base name for clones from this machine'), + required=True + ) - lenName = gui.NumericField(length=1, label=_('Name Length'), defvalue=5, order=7, - tooltip=_('Size of numeric part for the names of these machines (between 3 and 6)'), required=True) + lenName = gui.NumericField( + length=1, + label=_('Name Length'), + defvalue=5, + order=7, + tooltip=_('Size of numeric part for the names of these machines (between 3 and 6)'), + required=True + ) - display = gui.ChoiceField(label=_('Display'), rdonly=False, order=8, - tooltip=_('Display type (only for administration purposes)'), - values=[gui.choiceItem('spice', 'Spice'), - gui.choiceItem('vnc', 'Vnc') - ], - defvalue='1' # Default value is the ID of the choicefield - ) + display = gui.ChoiceField( + label=_('Display'), + rdonly=False, + order=8, + tooltip=_('Display type (only for administration purposes)'), + values=[ + gui.choiceItem('spice', 'Spice'), + gui.choiceItem('vnc', 'Vnc') + ], + defvalue='1' # Default value is the ID of the choicefield + ) ov = gui.HiddenField() ev = gui.HiddenField() # We need to keep the env so we can instantiate the Provider @@ -347,3 +390,8 @@ class OVirtLinkedService(Service): ''' return self.display.value + def getConsoleConnection(self, machineId): + return self.parent().getConsoleConnection(machineId) + + def desktopLogin(self, machineId, username, password, domain): + return self.parent().desktopLogin(machineId, username, password, domain) diff --git a/server/src/uds/services/OVirt/OVirtProvider.py b/server/src/uds/services/OVirt/OVirtProvider.py index 12c17e6bd..7a0025e3b 100644 --- a/server/src/uds/services/OVirt/OVirtProvider.py +++ b/server/src/uds/services/OVirt/OVirtProvider.py @@ -45,6 +45,8 @@ from client import oVirtClient import logging +__updated__ = '2015-05-09' + logger = logging.getLogger(__name__) CACHE_TIME_FOR_SERVER = 1800 @@ -370,6 +372,14 @@ class Provider(ServiceProvider): def getMacRange(self): return self.macsRange.value + def getConsoleConnection(self, machineId): + return self.__getApi().getConsoleConnection(machineId) + + def desktopLogin(self, machineId, username, password, domain): + ''' + ''' + return self.__getApi().desktopLogin(machineId, username, password, domain) + @staticmethod def test(env, data): ''' diff --git a/server/src/uds/services/OVirt/client/oVirtClient.py b/server/src/uds/services/OVirt/client/oVirtClient.py index 8f0bb2a72..82e4d01bf 100644 --- a/server/src/uds/services/OVirt/client/oVirtClient.py +++ b/server/src/uds/services/OVirt/client/oVirtClient.py @@ -10,6 +10,8 @@ from ovirtsdk.api import API import threading import logging +__updated__ = '2015-05-09' + logger = logging.getLogger(__name__) lock = threading.Lock() @@ -360,20 +362,30 @@ class Client(object): if vm.get_status().get_state() != 'down': raise Exception('Machine must be in down state to publish it') + print vm.disks.list() + # Create disks description to be created in specified storage domain, one for each disk sd = params.StorageDomains(storage_domain=[params.StorageDomain(id=storageId)]) dsks = [] for dsk in vm.disks.list(): - dsks.append(params.Disk(id=dsk.get_id(), storage_domains=sd)) + dsks.append(params.Disk(id=dsk.get_id(), storage_domains=sd, name='test', alias='test')) + # dsks.append(dsk) disks = params.Disks(disk=dsks) # Create display description - display = params.Display(type_=displayType) + # display = params.Display(type_=displayType) + + # TODO: Restore proper template creation mechanism + template = params.Template( + name=name, + # vm=params.VM(id=vm.get_id(), disks=disks), + vm=params.VM(id=vm.get_id()), + cluster=params.Cluster(id=cluster.get_id()), + description=comments + ) - template = params.Template(name=name, vm=params.VM(id=vm.get_id(), disks=disks), - cluster=params.Cluster(id=cluster.get_id()), description=comments) # display=display) return api.templates.add(template).get_id() @@ -622,7 +634,7 @@ class Client(object): finally: lock.release() - def getConnetcionInfo(self, machineId): + def getConsoleConnection(self, machineId): ''' Gets the connetion info for the specified machine ''' @@ -652,3 +664,6 @@ class Client(object): finally: lock.release() + + def desktopLogin(self, machineId, username, password, domain): + pass diff --git a/server/src/uds/transports/RDP/TSRDPTransport.py b/server/src/uds/transports/RDP/TSRDPTransport.py index 0da536b63..e79ab1694 100644 --- a/server/src/uds/transports/RDP/TSRDPTransport.py +++ b/server/src/uds/transports/RDP/TSRDPTransport.py @@ -46,7 +46,6 @@ from .RDPFile import RDPFile import logging import random import string -import time logger = logging.getLogger(__name__) diff --git a/server/src/uds/transports/SPICE/BaseSPICETransport.py b/server/src/uds/transports/SPICE/BaseSPICETransport.py index 8bd660e57..012458d8d 100644 --- a/server/src/uds/transports/SPICE/BaseSPICETransport.py +++ b/server/src/uds/transports/SPICE/BaseSPICETransport.py @@ -44,6 +44,9 @@ from uds.services.OVirt.OVirtProvider import Provider as oVirtProvider import logging import os +__updated__ = '2015-05-10' + + logger = logging.getLogger(__name__) READY_CACHE_TIMEOUT = 30 @@ -59,26 +62,26 @@ class BaseSpiceTransport(Transport): allowedProviders = oVirtProvider.offers useEmptyCreds = gui.CheckBoxField( - label=_('Empty creds'), order=1, + label=_('Empty creds'), tooltip=_('If checked, the credentials used to connect will be emtpy') ) fixedName = gui.TextField( - label=_('Username'), order=2, + label=_('Username'), tooltip=_('If not empty, this username will be always used as credential') ) fixedPassword = gui.PasswordField( - label=_('Password'), order=3, + label=_('Password'), tooltip=_('If not empty, this password will be always used as credential') ) serverCertificate = gui.TextField( - order=2, + order=4, length=4096, multiline=4, label=_('Certificate'), - tooltip=_('Server certificate (public), can be found on your ovirt engine, probably at /etc/pki/ovirt-engine/certs/ca.der'), + tooltip=_('Server certificate (public), can be found on your ovirt engine, probably at /etc/pki/ovirt-engine/certs/ca.der (Use the contents of this file).'), required=True ) diff --git a/server/src/uds/transports/SPICE/RemoteViewerFile.py b/server/src/uds/transports/SPICE/RemoteViewerFile.py index 7817d488e..a721ce3d1 100644 --- a/server/src/uds/transports/SPICE/RemoteViewerFile.py +++ b/server/src/uds/transports/SPICE/RemoteViewerFile.py @@ -3,25 +3,29 @@ Created on May 6, 2015 @author: dkmaster ''' +from __future__ import unicode_literals +import six +import os +__updated__ = '2015-05-10' -''' -[virt-viewer] -type=spice -host=ovirtnode1.dkmon.com -port=5900 -password=S9MATvnrQNGr -tls-port=5901 -fullscreen=0 -title=ovirt00004:%d - Press SHIFT+F12 to Release Cursor -enable-smartcard=0 -enable-usb-autoshare=1 -delete-this-file=1 + +TEMPLATE = '''[virt-viewer] +type={type} +host={host} +port={port} +password={password} +tls-port={tls_port} +fullscreen={fullscreen} +title={title}:%d - Press SHIFT+F12 to Release Cursor +enable-smartcard={smartcard} +enable-usb-autoshare={usb_auto_share} +delete-this-file={delete_file} usb-filter=-1,-1,-1,-1,0 tls-ciphers=DEFAULT -host-subject=O=dkmon.com,CN=ovirtnode1.dkmon.com -ca=-----BEGIN CERTIFICATE-----\nMIIDsjCCApqgAwIBAgICEAAwDQYJKoZIhvcNAQEFBQAwQTELMAkGA1UEBhMCVVMxEjAQBgNVBAoT\nCWRrbW9uLmNvbTEeMBwGA1UEAxMVb3ZpcnQuZGttb24uY29tLjk5MTAxMCIXETEzMTIxMTE5MDA0\nNCswMDAwFw0yMzEyMTAxOTAwNDRaMEExCzAJBgNVBAYTAlVTMRIwEAYDVQQKEwlka21vbi5jb20x\nHjAcBgNVBAMTFW92aXJ0LmRrbW9uLmNvbS45OTEwMTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC\nAQoCggEBAMeMD3njBOLjuS5XQY0kUu3+dT5S0HUhk2RyPv0Bf59Zun215jLX7qJLrDWCxq8xcdB0\n79Krn2wm+QpPBArSJGVZNXkwQSqnmQK7PGuC119wfOx/bQbgHGJuL6XzuRnLn1xMmcp9N33Q+Cic\nkV5B8bVF+bV5FUWzDbSQKsWJUMFwUXd7px9mZJWBCkY4cOoXdhdu5EMGWcEm2e4RkE+Fb611RAU2\nPL1iJwEu1qtG/OYvWh8DsO9OfFP4dZuJhy2oXmKudHgalNCm8hWYa498c1DA/uXZCGLjoN5en9yy\nXU2wkTDJGA0M95mkGlwoIaNXJMM4i4Q5lmzkU6xntp3/zNkCAwEAAaOBrzCBrDAdBgNVHQ4EFgQU\nOQAXE0qEasnOi3qEFFtMg19GqqYwagYDVR0jBGMwYYAUOQAXE0qEasnOi3qEFFtMg19GqqahRaRD\nMEExCzAJBgNVBAYTAlVTMRIwEAYDVQQKEwlka21vbi5jb20xHjAcBgNVBAMTFW92aXJ0LmRrbW9u\nLmNvbS45OTEwMYICEAAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwDQYJKoZIhvcN\nAQEFBQADggEBABDS5koE1TcBf8hvRP86AEu07KfWby/BvWXMcGuWRgPnkjrLS0mYshXx2Y40Pblm\nYm/DHXtefrDHJ203T/zkuCLtMSI28peeyX5HS32lGhVAMaylKrQ4mRTBQ+TM2hVLyBv7o16FUcei\nBuGNsm6F8b1RtrGTvSlkNxDUU3haDDH6gRMmMjgYrFqVMrozlPgPyHlFc4A1Q9rM/WIXtRioFgAz\ntCL1n5PK61ZIjk6j6a/upj6jYDfq1G0hpR9XOV8CD1bY3ZaCaMwOaILf1yIzQFqNDmx0p5e949at\nZIflG2pSv/5NA7PoRPF2tHf/PfrNmkA81R03dRXps1UAGg5ds3c=\n-----END CERTIFICATE-----\n +host-subject={host_subject} +ca={ca} toggle-fullscreen=shift+f11 release-cursor=shift+f12 secure-attention=ctrl+alt+end @@ -30,4 +34,53 @@ secure-channels=main;inputs;cursor;playback;record;display;usbredir;smartcard class RemoteViewerFile(object): - pass + type = 'spice' + host = None + port = None + tls_port = None + password = None + fullscreen = False + title = 'UDS Enterprise' + host_subject = '' + ca = '' + + smartcard = False + usb_auto_share = True + + delete_file = True + + def __init__(self, host, port, tls_port, password, ca, host_subject, fullscreen=False): + self.host = host + self.port = port + self.tls_port = tls_port + self.password = password + self.ca = ca + self.host_subject = host_subject + self.fullscreen = False + + @property + def as_file(self): + return self.get() + + def get(self): + fullscreen = '01'[self.fullscreen] + smartcard = '01'[self.smartcard] + delete_file = '01'[self.delete_file] + usb_auto_share = '01'[self.usb_auto_share] + + ca = self.ca.strip().replace('\n', '\\\\n') # So we get '\\n' and script works fine after replacement + + return TEMPLATE.format( + type=self.type, + host=self.host, + port=self.port, + tls_port=self.tls_port, + password=self.password, + fullscreen=fullscreen, + title=self.title, + smartcard=smartcard, + usb_auto_share=usb_auto_share, + delete_file=delete_file, + host_subject=self.host_subject, + ca=ca + ) diff --git a/server/src/uds/transports/SPICE/SPICETransport.py b/server/src/uds/transports/SPICE/SPICETransport.py index 5356f4633..96ed0ddd4 100644 --- a/server/src/uds/transports/SPICE/SPICETransport.py +++ b/server/src/uds/transports/SPICE/SPICETransport.py @@ -32,16 +32,16 @@ ''' from django.utils.translation import ugettext_noop as _ -from uds.core.managers.UserPrefsManager import CommonPrefs from uds.core.util import OsDetector from uds.core.util import tools from .BaseSPICETransport import BaseSpiceTransport +from .RemoteViewerFile import RemoteViewerFile import logging -logger = logging.getLogger(__name__) +__updated__ = '2015-05-10' -READY_CACHE_TIMEOUT = 30 +logger = logging.getLogger(__name__) class SPICETransport(BaseSpiceTransport): @@ -51,7 +51,7 @@ class SPICETransport(BaseSpiceTransport): ''' typeName = _('SPICE Transport (direct)') typeType = 'SPICETransport' - typeDescription = _('SPICE Transport for direct connection') + typeDescription = _('SPICE Transport for direct connection (EXPERIMENTAL)') useEmptyCreds = BaseSpiceTransport.useEmptyCreds fixedName = BaseSpiceTransport.fixedName @@ -59,69 +59,29 @@ class SPICETransport(BaseSpiceTransport): serverCertificate = BaseSpiceTransport.serverCertificate def getUDSTransportScript(self, userService, transport, ip, os, user, password, request): - # We use helper to keep this clean - prefs = user.prefs('rdp') + userServiceInstance = userService.getInstance() - ci = self.getConnectionInfo(userService, user, password) - username, password, domain = ci['username'], ci['password'], ci['domain'] + con = userServiceInstance.getConsoleConnection() - width, height = CommonPrefs.getWidthHeight(prefs) - depth = CommonPrefs.getDepth(prefs) + logger.debug('Connection data: {}'.format(con)) -# r = SPICEFile(width == -1 or height == -1, width, height, depth, target=os['OS']) -# r.address = '{}:{}'.format(ip, 3389) -# r.username = username -# r.password = password -# r.domain = domain -# r.redirectPrinters = self.allowPrinters.isTrue() -# r.redirectSmartcards = self.allowSmartcards.isTrue() -# r.redirectDrives = self.allowDrives.isTrue() -# r.redirectSerials = self.allowSerials.isTrue() -# r.showWallpaper = self.wallpaper.isTrue() -# r.multimon = self.multimon.isTrue() -# -# # data -# data = { -# 'os': os['OS'], -# 'ip': ip, -# 'port': 3389, -# 'username': username, -# 'password': password, -# 'hasCredentials': username != '' and password != '', -# 'domain': domain, -# 'width': width, -# 'height': height, -# 'depth': depth, -# 'printers': self.allowPrinters.isTrue(), -# 'smartcards': self.allowSmartcards.isTrue(), -# 'drives': self.allowDrives.isTrue(), -# 'serials': self.allowSerials.isTrue(), -# 'compression': True, -# 'wallpaper': self.wallpaper.isTrue(), -# 'multimon': self.multimon.isTrue(), -# 'fullScreen': width == -1 or height == -1, -# 'this_server': request.build_absolute_uri('/'), -# 'r': r, -# } -# -# m = tools.DictAsObj(data) -# -# if m.domain != '': -# m.usernameWithDomain = '{}\\\\{}'.format(m.domain, m.username) -# else: -# m.usernameWithDomain = m.username -# -# if m.os == OsDetector.Windows: -# m.r.password = '{password}' -# -# os = { -# OsDetector.Windows: 'windows', -# OsDetector.Linux: 'linux', -# OsDetector.Macintosh: 'macosx' -# -# }.get(m.os) -# -# if os is None: -# return super(SPICETransport, self).getUDSTransportScript(self, userService, transport, ip, os, user, password, request) -# -# return self.getScript('scripts/{}/direct.py'.format(os)).format(m=m) + port, secure_port = con['port'], con['secure_port'] + port = -1 if port is None else port + secure_port = -1 if secure_port is None else secure_port + + r = RemoteViewerFile(con['address'], port, secure_port, con['ticket']['value'], self.serverCertificate.value, con['cert_subject'], fullscreen=False) + + m = tools.DictAsObj({ + 'r': r + }) + + os = { + OsDetector.Windows: 'windows', + OsDetector.Linux: 'linux', + OsDetector.Macintosh: 'macosx' + }.get(os.OS) + + if os is None: + return super(SPICETransport, self).getUDSTransportScript(self, userService, transport, ip, os, user, password, request) + + return self.getScript('scripts/{}/direct.py'.format(os)).format(m=m) diff --git a/server/src/uds/transports/SPICE/TSPICETransport.py b/server/src/uds/transports/SPICE/TSPICETransport.py index a35229538..7eef526b6 100644 --- a/server/src/uds/transports/SPICE/TSPICETransport.py +++ b/server/src/uds/transports/SPICE/TSPICETransport.py @@ -32,25 +32,24 @@ ''' from django.utils.translation import ugettext_noop as _ -from uds.core.managers.UserPrefsManager import CommonPrefs from uds.core.ui.UserInterface import gui from uds.core.transports.BaseTransport import Transport from uds.core.transports import protocols -from uds.models import TicketStore from uds.core.util import OsDetector from uds.core.util import tools +from uds.models import TicketStore from .BaseSPICETransport import BaseSpiceTransport +from .RemoteViewerFile import RemoteViewerFile import logging import random import string -import time + +__updated__ = '2015-05-10' logger = logging.getLogger(__name__) -READY_CACHE_TIMEOUT = 30 - class TSPICETransport(BaseSpiceTransport): ''' @@ -59,17 +58,13 @@ class TSPICETransport(BaseSpiceTransport): ''' typeName = _('SPICE Transport (tunneled)') typeType = 'TSSPICETransport' - typeDescription = _('SPICE Transport for tunneled connection') + typeDescription = _('SPICE Transport for tunneled connection (EXPERIMENTAL)') iconFile = 'rdp.png' needsJava = True # If this transport needs java for rendering protocol = protocols.SPICE tunnelServer = gui.TextField(label=_('Tunnel server'), order=1, tooltip=_('IP or Hostname of tunnel server sent to client device ("public" ip) and port. (use HOST:PORT format)')) - tunnelCheckServer = gui.TextField(label=_('Tunnel host check'), order=2, tooltip=_('If not empty, this server will be used to check if service is running before assigning it to user. (use HOST:PORT format)')) - useEmptyCreds = BaseSpiceTransport.useEmptyCreds - fixedName = BaseSpiceTransport.fixedName - fixedPassword = BaseSpiceTransport.fixedPassword serverCertificate = BaseSpiceTransport.serverCertificate def initialize(self, values): @@ -78,80 +73,40 @@ class TSPICETransport(BaseSpiceTransport): raise Transport.ValidationException(_('Must use HOST:PORT in Tunnel Server Field')) def getUDSTransportScript(self, userService, transport, ip, os, user, password, request): - # We use helper to keep this clean - prefs = user.prefs('rdp') + userServiceInstance = userService.getInstance() - ci = self.getConnectionInfo(userService, user, password) - username, password, domain = ci['username'], ci['password'], ci['domain'] - - width, height = CommonPrefs.getWidthHeight(prefs) - depth = CommonPrefs.getDepth(prefs) + # Spice connection + con = userServiceInstance.getConsoleConnection() + port, secure_port = con['port'], con['secure_port'] + port = -1 if port is None else port + secure_port = -1 if secure_port is None else secure_port + # Ticket tunpass = ''.join(random.choice(string.letters + string.digits) for _i in range(12)) tunuser = TicketStore.create(tunpass) sshHost, sshPort = self.tunnelServer.value.split(':') - logger.debug('Username generated: {0}, password: {1}'.format(tunuser, tunpass)) + r = RemoteViewerFile('127.0.0.1', '{port}', '{secure_port}', con['ticket']['value'], self.serverCertificate.value, con['cert_subject'], fullscreen=False) -# r = SPICEFile(width == -1 or height == -1, width, height, depth, target=os['OS']) -# r.address = '{address}' -# r.username = username -# r.password = password -# r.domain = domain -# r.redirectPrinters = self.allowPrinters.isTrue() -# r.redirectSmartcards = self.allowSmartcards.isTrue() -# r.redirectDrives = self.allowDrives.isTrue() -# r.redirectSerials = self.allowSerials.isTrue() -# r.showWallpaper = self.wallpaper.isTrue() -# r.multimon = self.multimon.isTrue() -# -# -# # data -# data = { -# 'os': os['OS'], -# 'ip': ip, -# 'tunUser': tunuser, -# 'tunPass': tunpass, -# 'tunHost': sshHost, -# 'tunPort': sshPort, -# 'username': username, -# 'password': password, -# 'hasCredentials': username != '' and password != '', -# 'domain': domain, -# 'width': width, -# 'height': height, -# 'depth': depth, -# 'printers': self.allowPrinters.isTrue(), -# 'smartcards': self.allowSmartcards.isTrue(), -# 'drives': self.allowDrives.isTrue(), -# 'serials': self.allowSerials.isTrue(), -# 'compression': True, -# 'wallpaper': self.wallpaper.isTrue(), -# 'multimon': self.multimon.isTrue(), -# 'fullScreen': width == -1 or height == -1, -# 'this_server': request.build_absolute_uri('/'), -# 'r': r, -# } -# -# m = tools.DictAsObj(data) -# -# if m.domain != '': -# m.usernameWithDomain = '{}\\\\{}'.format(m.domain, m.username) -# else: -# m.usernameWithDomain = m.username -# -# if m.os == OsDetector.Windows: -# r.password = '{password}' -# -# os = { -# OsDetector.Windows: 'windows', -# OsDetector.Linux: 'linux', -# OsDetector.Macintosh: 'macosx' -# -# }.get(m.os) -# -# if os is None: -# return super(TSPICETransport, self).getUDSTransportScript(self, userService, transport, ip, os, user, password, request) -# -# return self.getScript('scripts/{}/tunnel.py'.format(os)).format(m=m) + m = tools.DictAsObj({ + 'r': r, + 'tunUser': tunuser, + 'tunPass': tunpass, + 'tunHost': sshHost, + 'tunPort': sshPort, + 'ip': con['address'], + 'port': port, + 'secure_port': secure_port + }) + + os = { + OsDetector.Windows: 'windows', + OsDetector.Linux: 'linux', + OsDetector.Macintosh: 'macosx' + }.get(os.OS) + + if os is None: + return super(TSPICETransport, self).getUDSTransportScript(self, userService, transport, ip, os, user, password, request) + + return self.getScript('scripts/{}/tunnel.py'.format(os)).format(m=m) diff --git a/server/src/uds/transports/SPICE/__init__.py b/server/src/uds/transports/SPICE/__init__.py index 68d8d4d39..52181f847 100644 --- a/server/src/uds/transports/SPICE/__init__.py +++ b/server/src/uds/transports/SPICE/__init__.py @@ -35,11 +35,3 @@ from django.utils.translation import ugettext_noop as _ from uds.core.managers.UserPrefsManager import UserPrefsManager, CommonPrefs from .SPICETransport import SPICETransport from .TSPICETransport import TSPICETransport - -UserPrefsManager.manager().registerPrefs('rdp', - _('Remote Desktop Protocol'), - [ - CommonPrefs.screenSizePref, - CommonPrefs.depthPref - ] - ) diff --git a/server/src/uds/transports/SPICE/scripts/linux/direct.py b/server/src/uds/transports/SPICE/scripts/linux/direct.py index d1ef5afb3..c21e27c84 100644 --- a/server/src/uds/transports/SPICE/scripts/linux/direct.py +++ b/server/src/uds/transports/SPICE/scripts/linux/direct.py @@ -2,61 +2,24 @@ # Saved as .py for easier editing from __future__ import unicode_literals -# pylint: disable=import-error, no-name-in-module, too-many-format-args, undefined-variable, invalid-sequence-index -from PyQt4 import QtCore, QtGui +# pylint: disable=import-error, no-name-in-module import subprocess -import re from uds import tools # @UnresolvedImport -import six +executable = tools.findApp('remote-viewer') - -def execNewXFreeRdp(parent, xfreerdp): - import subprocess # @Reimport - params = [xfreerdp] + {m.r.as_new_xfreerdp_params} + ['/v:{m.r.address}'] # @UndefinedVariable - tools.addTaskToWait(subprocess.Popen(params)) - - -def execRdesktop(parent, rdesktop): - import subprocess # @Reimport - params = [rdesktop] + {m.r.as_rdesktop_params} + ['{m.r.address}'] # @UndefinedVariable - p = subprocess.Popen(params, stdin=subprocess.PIPE) - if '{m.password}' != '': - p.stdin.write('{m.password}') - p.stdin.close() - tools.addTaskToWait(p) - -# Try to locate a "valid" version of xfreerdp as first option (<1.1 does not allows drive redirections, so it will not be used if found) -xfreerdp = tools.findApp('xfreerdp') -rdesktop = tools.findApp('rdesktop') -fnc, app = None, None - -if rdesktop is not None: - fnc, app = execRdesktop, rdesktop - -if xfreerdp is not None: - # Check for nice version - try: - try: - version = subprocess.check_output([xfreerdp, '--version']) - except subprocess.CalledProcessError as e: - version = e.output - - version = float(re.search(r'version ([0-9]*\.[0-9]*)', version).groups()[0]) - if version < 1.1: - raise Exception() - else: - fnc, app = execNewXFreeRdp, xfreerdp - - except Exception as e: # Valid version not found, pass to check rdesktop - # QtGui.QMessageBox.critical(parent, 'Notice', six.text_type(e), QtGui.QMessageBox.Ok) # @UndefinedVariable - pass - -if app is None or fnc is None: - raise Exception('''
You need to have installed xfreerdp (>= 1.1) or rdesktop, and have them in your PATH in order to connect to this UDS service.
-Please, install apropiate package for your system.
-Also note that xfreerdp prior to version 1.1 will not be taken into consideration.
+if executable is None: + raise Exception('''You need to have installed virt-viewer to connect to this UDS service.
++ Please, install appropriate package for your Linux system. (probably named something like remote-viewer) +
''') -else: - fnc(parent, app) # @UndefinedVariable + +theFile = '''{m.r.as_file}''' + +filename = tools.saveTempFile(theFile) + +subprocess.Popen([executable, filename]) + +# QtGui.QMessageBox.critical(parent, 'Notice', filename + ", " + executable, QtGui.QMessageBox.Ok) diff --git a/server/src/uds/transports/SPICE/scripts/linux/tunnel.py b/server/src/uds/transports/SPICE/scripts/linux/tunnel.py index 2619290b2..61784dbe7 100644 --- a/server/src/uds/transports/SPICE/scripts/linux/tunnel.py +++ b/server/src/uds/transports/SPICE/scripts/linux/tunnel.py @@ -2,68 +2,47 @@ # Saved as .py for easier editing from __future__ import unicode_literals -# pylint: disable=import-error, no-name-in-module, too-many-format-args, undefined-variable, invalid-sequence-index -from PyQt4 import QtCore, QtGui +# pylint: disable=import-error, no-name-in-module, undefined-variable import subprocess -import re -from uds.forward import forward # @UnresolvedImport from uds import tools # @UnresolvedImport +from uds.forward import forward # @UnresolvedImport -import six +executable = tools.findApp('remote-viewer') - -def execNewXFreeRdp(parent, xfreerdp, port): - import subprocess # @Reimport - params = [xfreerdp] + {m.r.as_new_xfreerdp_params} + ['/v:127.0.0.1:{{}}'.format(port)] # @UndefinedVariable - tools.addTaskToWait(subprocess.Popen(params)) - - -def execRdesktop(parent, rdesktop, port): - import subprocess # @Reimport - params = [rdesktop] + {m.r.as_rdesktop_params} + ['127.0.0.1:{{}}'.format(port)] # @UndefinedVariable - p = subprocess.Popen(params, stdin=subprocess.PIPE) - if {m.hasCredentials}: # @UndefinedVariable - p.stdin.write('{m.password}') - p.stdin.close() - tools.addTaskToWait(p) - -# Try to locate a "valid" version of xfreerdp as first option (<1.1 does not allows drive redirections, so it will not be used if found) -xfreerdp = tools.findApp('xfreerdp') -rdesktop = tools.findApp('rdesktop') -fnc, app = None, None - -if rdesktop is not None: - fnc, app = execRdesktop, rdesktop - -if xfreerdp is not None: - # Check for nice version - try: - try: - version = subprocess.check_output([xfreerdp, '--version']) - except subprocess.CalledProcessError as e: - version = e.output - - version = float(re.search(r'version ([0-9]*\.[0-9]*)', version).groups()[0]) - if version < 1.1: - raise Exception() - else: - fnc, app = execNewXFreeRdp, xfreerdp - - except Exception as e: # Valid version not found, pass to check rdesktop - # QtGui.QMessageBox.critical(parent, 'Notice', six.text_type(e), QtGui.QMessageBox.Ok) # @UndefinedVariable - pass - -if app is None or fnc is None: - raise Exception('''You need to have installed xfreerdp (>= 1.1) or rdesktop, and have them in your PATH in order to connect to this UDS service.
-Please, install apropiate package for your system.
-Also note that xfreerdp prior to version 1.1 will not be taken into consideration.
+if executable is None: + raise Exception('''You need to have installed virt-viewer to connect to this UDS service.
++ Please, install appropriate package for your system. +
++ Please, install appropriate package for your Linux system. (probably named something like virt-viewer) +
''') -else: - # Open tunnel - forwardThread, port = forward('{m.tunHost}', '{m.tunPort}', '{m.tunUser}', '{m.tunPass}', '{m.ip}', 3389) - if forwardThread.status == 2: + +if {m.port} != -1: # @UndefinedVariable + forwardThread1, port = forward('{m.tunHost}', '{m.tunPort}', '{m.tunUser}', '{m.tunPass}', '{m.ip}', {m.port}) # @UndefinedVariable + + if forwardThread1.status == 2: raise Exception('Unable to open tunnel') +else: + port = -1 - fnc(parent, app, port) # @UndefinedVariable +if {m.secure_port} != -1: # @UndefinedVariable + forwardThread2, secure_port = forward('{m.tunHost}', '{m.tunPort}', '{m.tunUser}', '{m.tunPass}', '{m.ip}', {m.secure_port}) # @UndefinedVariable + + if forwardThread2.status == 2: + raise Exception('Unable to open tunnel') +else: + secure_port = -1 + +theFile = '''{m.r.as_file}'''.format( + secure_port=secure_port, + port=port +) + +filename = tools.saveTempFile(theFile) + + +subprocess.Popen([executable, filename]) diff --git a/server/src/uds/transports/SPICE/scripts/macosx/direct.py b/server/src/uds/transports/SPICE/scripts/macosx/direct.py index 04e248a89..e6045576e 100644 --- a/server/src/uds/transports/SPICE/scripts/macosx/direct.py +++ b/server/src/uds/transports/SPICE/scripts/macosx/direct.py @@ -2,110 +2,34 @@ # Saved as .py for easier editing from __future__ import unicode_literals -# pylint: disable=import-error, no-name-in-module, too-many-format-args, undefined-variable, invalid-sequence-index -from PyQt4 import QtCore, QtGui -import subprocess +# pylint: disable=import-error, no-name-in-module import os -import urllib +import subprocess from uds import tools # @UnresolvedImport -import six +remoteViewer = '/Applications/RemoteViewer.app/Contents/MacOS/RemoteViewer' + +if not os.path.isfile(remoteViewer): + raise Exception('''You need to have installed virt-viewer to connect to this UDS service.
++ Please, install appropriate package for your system. +
+ +
+ Please, note that in order to UDS Connector to work correctly, you must copy the Remote Viewer app to your Applications Folder.
+ Also remember, that in order to allow this app to run on your system, you must open it one time once it is copied to your App folder
+
Microsoft Remote Desktop Connection not found
-In order to connect to UDS RDP Sessions, you need to have at least one of the following:
-
Microsoft Remote Desktop Connection version 2. (Recommended)
-You can get it from this link
-Remember that you need to use the One from the Microsoft site (the link provided), not the one from the AppStore
-CoRD (A bit unstable from 10.7 onwards)
-You can get it from this link
-If both apps are installed, Remote Desktop Connection will be used as first option
- -''', QtGui.QMessageBox.Ok) -elif executable == msrdc: - try: - if {m.hasCredentials}: # @UndefinedVariable - subprocess.call( - [ - 'security', - 'add-generic-password', - '-w', '{m.password}', - '-U', - '-a', '{m.usernameWithDomain}', - '-s', 'Remote Desktop Connection 2 Password for {m.ip}', - '-T', '/Applications/Remote Desktop Connection.app', - ] - ) - tools.addExecBeforeExit(onExit) - # Call and wait for exit - tools.addTaskToWait(subprocess.Popen([executable, filename])) - - tools.addFileToUnlink(filename) - except Exception as e: - QtGui.QMessageBox.critical(parent, 'Notice', six.text_type(e), QtGui.QMessageBox.Ok) # @UndefinedVariable -else: # CoRD - url = 'rdp://' - - username, domain = '{m.username}', '{m.domain}' - - if username != '': - url += username - if '{m.password}' != '': - url += ':' + urllib.quote('{m.password}') - url += '@' - url += '{m.ip}/' - if domain != '': - url += domain - - url += '?screenDepth={m.r.bpp}' - - if {m.r.fullScreen}: # @UndefinedVariable - url += '&fullscreen=true' - else: - url += 'screenWidth={m.r.width}&screenHeight={m.r.height}' - - url += '&forwardAudio=' + '01'[{m.r.redirectAudio}] # @UndefinedVariable - - if {m.r.redirectDrives}: # @UndefinedVariable - url += '&forwardDisks=true' - - if {m.r.redirectPrinters}: # @UndefinedVariable - url += '&forwardPrinters=true' - - tools.addTaskToWait(subprocess.Popen(['open', url])) +subprocess.Popen([remoteViewer, filename]) diff --git a/server/src/uds/transports/SPICE/scripts/macosx/tunnel.py b/server/src/uds/transports/SPICE/scripts/macosx/tunnel.py index c546fe6ae..ecb25a8e5 100644 --- a/server/src/uds/transports/SPICE/scripts/macosx/tunnel.py +++ b/server/src/uds/transports/SPICE/scripts/macosx/tunnel.py @@ -2,119 +2,51 @@ # Saved as .py for easier editing from __future__ import unicode_literals -# pylint: disable=import-error, no-name-in-module, too-many-format-args, undefined-variable, invalid-sequence-index -from PyQt4 import QtCore, QtGui -import subprocess +# pylint: disable=import-error, no-name-in-module, undefined-variable import os -import urllib -from uds.forward import forward # @UnresolvedImport +import subprocess from uds import tools # @UnresolvedImport +from uds.forward import forward # @UnresolvedImport -import six +remoteViewer = '/Applications/RemoteViewer.app/Contents/MacOS/RemoteViewer' -# First, try to locate Remote Desktop Connection (version 2, from Microsoft website, not the app store one) -msrdc = '/Applications/Remote Desktop Connection.app/Contents/MacOS/Remote Desktop Connection' -cord = "/Applications/CoRD.app/Contents/MacOS/CoRD" +if not os.path.isfile(remoteViewer): + raise Exception('''You need to have installed virt-viewer to connect to this UDS service.
++ Please, install appropriate package for your system. +
+ +
+ Please, note that in order to UDS Connector to work correctly, you must copy the Remote Viewer app to your Applications Folder.
+ Also remember, that in order to allow this app to run on your system, you must open it one time once it is copied to your App folder
+
Microsoft Remote Desktop Connection not found
-In order to connect to UDS RDP Sessions, you need to have at least one of the following:
-
Microsoft Remote Desktop Connection version 2. (Recommended)
-You can get it from this link
-Remember that you need to use the One from the Microsoft site (the link provided), not the one from the AppStore
-CoRD (A bit unstable from 10.7 onwards)
-You can get it from this link
-If both apps are installed, Remote Desktop Connection will be used as first option
- -''', QtGui.QMessageBox.Ok) - - -forwardThread, port = forward('{m.tunHost}', '{m.tunPort}', '{m.tunUser}', '{m.tunPass}', '{m.ip}', 3389) - -if forwardThread.status == 2: - raise Exception('Unable to open tunnel') - + if forwardThread2.status == 2: + raise Exception('Unable to open tunnel') else: - theFile = '''{m.r.as_file}'''.format( - address='127.0.0.1:{{}}'.format(port) - ) - filename = tools.saveTempFile(theFile) - tools.addFileToUnlink(filename) + secure_port = -1 - if executable == msrdc: - try: - if {m.hasCredentials}: # @UndefinedVariable - subprocess.call( - [ - 'security', - 'add-generic-password', - '-w', '{m.password}', - '-U', - '-a', '{m.username}', - '-s', 'Remote Desktop Connection 2 Password for 127.0.0.1'.format(port), - '-T', '/Applications/Remote Desktop Connection.app', - ] - ) - tools.addExecBeforeExit(onExit) - # Call but do not wait for exit - tools.addTaskToWait(subprocess.Popen([executable, filename])) +theFile = '''{m.r.as_file}'''.format( + secure_port=secure_port, + port=port +) - tools.addFileToUnlink(filename) - except Exception as e: - QtGui.QMessageBox.critical(parent, 'Notice', six.text_type(e), QtGui.QMessageBox.Ok) # @UndefinedVariable - else: # CoRD - url = 'rdp://' - username, domain = '{m.username}', '{m.domain}' +filename = tools.saveTempFile(theFile) - if username != '': - url += username - if '{m.password}' != '': - url += ':' + urllib.quote('{m.password}') - url += '@' - url += '127.0.0.1:3389/' - if domain != '': - url += domain - - url += '?screenDepth={m.r.bpp}' - - if {m.r.fullScreen}: # @UndefinedVariable - url += '&fullscreen=true' - else: - url += 'screenWidth={m.r.width}&screenHeight={m.r.height}' - - url += '&forwardAudio=' + '01'[{m.r.redirectAudio}] # @UndefinedVariable - - if {m.r.redirectDrives}: # @UndefinedVariable - url += '&forwardDisks=true' - - if {m.r.redirectPrinters}: # @UndefinedVariable - url += '&forwardPrinters=true' - - tools.addTaskToWait(subprocess.Popen(['open', url])) +subprocess.Popen([remoteViewer, filename]) diff --git a/server/src/uds/transports/SPICE/scripts/windows/direct.py b/server/src/uds/transports/SPICE/scripts/windows/direct.py index dcb5ef861..5b1753c72 100644 --- a/server/src/uds/transports/SPICE/scripts/windows/direct.py +++ b/server/src/uds/transports/SPICE/scripts/windows/direct.py @@ -3,21 +3,33 @@ from __future__ import unicode_literals # pylint: disable=import-error, no-name-in-module -from PyQt4 import QtCore, QtGui -import win32crypt # @UnresolvedImport import os +import glob import subprocess from uds import tools # @UnresolvedImport -import six +# Lets find remote viewer +# There is a bug that when installed, the remote viewer (at least 64 bits version) does not store correctly its path, so lets find it "a las bravas" +extraPaths = () +for env in ('PROGRAMFILES', 'PROGRAMW6432'): + if env in os.environ: + extraPaths += tuple(p + '\\bin' for p in glob.glob(os.environ[env] + '\\VirtViewer*')) -# The password must be encoded, to be included in a .rdp file, as 'UTF-16LE' before protecting (CtrpyProtectData) it in order to work with mstsc -theFile = '''{m.r.as_file}'''.format(password=win32crypt.CryptProtectData(six.binary_type('{m.password}'.encode('UTF-16LE')), None, None, None, None, 0x01).encode('hex')) +executable = tools.findApp('remote-viewer.exe', extraPaths) + +if executable is None: + raise Exception('''You need to have installed virt-viewer to connect to this UDS service.
++ Please, install appropriate package for your system. +
+ +''') + +theFile = '''{m.r.as_file}''' filename = tools.saveTempFile(theFile) -executable = tools.findApp('mstsc.exe') -subprocess.call([executable, filename]) -tools.addFileToUnlink(filename) -# QtGui.QMessageBox.critical(parent, 'Notice', filename + ", " + executable, QtGui.QMessageBox.Ok) +subprocess.Popen([executable, filename]) diff --git a/server/src/uds/transports/SPICE/scripts/windows/tunnel.py b/server/src/uds/transports/SPICE/scripts/windows/tunnel.py index e722ea58c..e8a6c7d92 100644 --- a/server/src/uds/transports/SPICE/scripts/windows/tunnel.py +++ b/server/src/uds/transports/SPICE/scripts/windows/tunnel.py @@ -2,35 +2,54 @@ # Saved as .py for easier editing from __future__ import unicode_literals -# pylint: disable=import-error, no-name-in-module, too-many-format-args, undefined-variable - -from PyQt4 import QtCore, QtGui -import win32crypt # @UnresolvedImport +# pylint: disable=import-error, no-name-in-module, undefined-variable import os +import glob import subprocess -from uds.forward import forward # @UnresolvedImport from uds import tools # @UnresolvedImport +from uds.forward import forward # @UnresolvedImport -import six +# Lets find remote viewer +# There is a bug that when installed, the remote viewer (at least 64 bits version) does not store correctly its path, so lets find it "a las bravas" +extraPaths = () +for env in ('PROGRAMFILES', 'PROGRAMW6432'): + if env in os.environ: + extraPaths += tuple(p + '\\bin' for p in glob.glob(os.environ[env] + '\\VirtViewer*')) -forwardThread, port = forward('{m.tunHost}', '{m.tunPort}', '{m.tunUser}', '{m.tunPass}', '{m.ip}', 3389) +executable = tools.findApp('remote-viewer.exe', extraPaths) -if forwardThread.status == 2: - raise Exception('Unable to open tunnel') +if executable is None: + raise Exception('''You need to have installed virt-viewer to connect to this UDS service.
++ Please, install appropriate package for your system. +
+ +''') + +if {m.port} != -1: # @UndefinedVariable + forwardThread1, port = forward('{m.tunHost}', '{m.tunPort}', '{m.tunUser}', '{m.tunPass}', '{m.ip}', {m.port}) # @UndefinedVariable + + if forwardThread1.status == 2: + raise Exception('Unable to open tunnel') +else: + port = -1 + +if {m.secure_port} != -1: # @UndefinedVariable + forwardThread2, secure_port = forward('{m.tunHost}', '{m.tunPort}', '{m.tunUser}', '{m.tunPass}', '{m.ip}', {m.secure_port}) # @UndefinedVariable + + if forwardThread2.status == 2: + raise Exception('Unable to open tunnel') +else: + secure_port = -1 -# The password must be encoded, to be included in a .rdp file, as 'UTF-16LE' before protecting (CtrpyProtectData) it in order to work with mstsc theFile = '''{m.r.as_file}'''.format( - password=win32crypt.CryptProtectData(six.binary_type('{m.password}'.encode('UTF-16LE')), None, None, None, None, 0x01).encode('hex'), - address='127.0.0.1:{{}}'.format(port) + secure_port=secure_port, + port=port ) filename = tools.saveTempFile(theFile) -executable = tools.findApp('mstsc.exe') -if executable is None: - raise Exception('Unable to find mstsc.exe') -subprocess.call([executable, filename]) -tools.addFileToUnlink(filename) - -# QtGui.QMessageBox.critical(parent, 'Notice', filename + ", " + executable, QtGui.QMessageBox.Ok) +subprocess.Popen([executable, filename])