def guiField(self, value): vals = [] for v in self._values: vals.append({'id': v[0], 'text': _(v[1])}) return gui.ChoiceField(label=_(self._label), rdonly=False, values=vals, defvalue=value, tooltip=_(self._label))
class ListReportUsers(ListReport): filename = 'users.pdf' def initialize(self, values): if values: auth = Authenticator.objects.get(uuid=self.authenticator.value) self.filename = auth.name + '.pdf' authenticator = gui.ChoiceField( label=_("Authenticator"), order=1, tooltip=_('Authenticator from where to list users'), required=True) name = _('Users list') # Report name description = _('List users of platform') # Report description uuid = '8cd1cfa6-ed48-11e4-83e5-10feed05884b' def initGui(self): logger.debug('Initializing gui') vals = [ gui.choiceItem(v.uuid, v.name) for v in Authenticator.objects.all() ] self.authenticator.setValues(vals) def generate(self): auth = Authenticator.objects.get(uuid=self.authenticator.value) users = auth.users.order_by('name') return self.templateAsPDF( 'uds/reports/lists/users.html', dct={ 'users': users, 'auth': auth.name, }, header=ugettext('Users List for {}').format(auth.name), water=ugettext('UDS Report of users in {}').format(auth.name))
class ListReportUsers(ListReport): filename = 'users.pdf' def initialize(self, values): if values: auth = Authenticator.objects.get(uuid=self.authenticator.value) self.filename = auth.name + '.pdf' authenticator = gui.ChoiceField( label=_("Authenticator"), order=1, tooltip=_('Authenticator from where to list users'), required=True) name = _('Users list') # Report name description = _('List users of platform') # Report description uuid = '8cd1cfa6-ed48-11e4-83e5-10feed05884b' def initGui(self): logger.debug('Initializing gui') vals = [ gui.choiceItem(v.uuid, v.name) for v in Authenticator.objects.all() ] self.authenticator.setValues(vals) def generate(self): auth = Authenticator.objects.get(uuid=self.authenticator.value) users = auth.users.order_by('name') output = StringIO.StringIO() report = UsersReport(queryset=users) report.title = _('Users List for {}').format(auth.name) report.generate_by(PDFGenerator, filename=output) return output.getvalue()
class BaseRDPTransport(Transport): """ Provides access via RDP to service. This transport can use an domain. If username processed by authenticator contains '@', it will split it and left-@-part will be username, and right password """ iconFile = 'rdp.png' protocol = protocols.RDP useEmptyCreds = gui.CheckBoxField( label=_('Empty creds'), order=11, tooltip=_('If checked, the credentials used to connect will be emtpy'), tab=gui.CREDENTIALS_TAB) fixedName = gui.TextField( label=_('Username'), order=12, tooltip=_( 'If not empty, this username will be always used as credential'), tab=gui.CREDENTIALS_TAB) fixedPassword = gui.PasswordField( label=_('Password'), order=13, tooltip=_( 'If not empty, this password will be always used as credential'), tab=gui.CREDENTIALS_TAB) withoutDomain = gui.CheckBoxField( label=_('Without Domain'), order=14, tooltip= _('If checked, the domain part will always be emptied (to connect to xrdp for example is needed)' ), tab=gui.CREDENTIALS_TAB) fixedDomain = gui.TextField( label=_('Domain'), order=15, tooltip= _('If not empty, this domain will be always used as credential (used as DOMAIN\\user)' ), tab=gui.CREDENTIALS_TAB) allowSmartcards = gui.CheckBoxField( label=_('Allow Smartcards'), order=20, tooltip=_( 'If checked, this transport will allow the use of smartcards'), tab=gui.PARAMETERS_TAB) allowPrinters = gui.CheckBoxField( label=_('Allow Printers'), order=21, tooltip=_( 'If checked, this transport will allow the use of user printers'), tab=gui.PARAMETERS_TAB) allowDrives = gui.ChoiceField( label=_('Allow Drives'), order=22, tooltip=_('Local drives redirection allowed'), defvalue='false', values=[ { 'id': 'false', 'text': 'None' }, { 'id': 'dynamic', 'text': 'Only PnP drives' }, { 'id': 'true', 'text': 'All drives' }, ], tab=gui.PARAMETERS_TAB) allowSerials = gui.CheckBoxField( label=_('Allow Serials'), order=23, tooltip=_( 'If checked, this transport will allow the use of user serial ports' ), tab=gui.PARAMETERS_TAB) allowClipboard = gui.CheckBoxField( label=_('Enable clipboard'), order=24, tooltip=_('If checked, copy-paste functions will be allowed'), tab=gui.PARAMETERS_TAB, defvalue=gui.TRUE) allowAudio = gui.CheckBoxField( label=_('Enable sound'), order=25, tooltip=_('If checked, sound will be redirected.'), tab=gui.PARAMETERS_TAB, defvalue=gui.TRUE) credssp = gui.CheckBoxField( label=_('Credssp Support'), order=26, tooltip=_('If checked, will enable Credentials Provider Support)'), tab=gui.PARAMETERS_TAB, defvalue=gui.TRUE) screenSize = gui.ChoiceField(label=_('Screen Size'), order=30, tooltip=_('Screen size for this transport'), defvalue='-1x-1', values=[ { 'id': '640x480', 'text': '640x480' }, { 'id': '800x600', 'text': '800x600' }, { 'id': '1024x768', 'text': '1024x768' }, { 'id': '1366x768', 'text': '1366x768' }, { 'id': '1920x1080', 'text': '1920x1080' }, { 'id': '-1x-1', 'text': 'Full screen' }, ], tab=gui.DISPLAY_TAB) colorDepth = gui.ChoiceField(label=_('Color depth'), order=31, tooltip=_('Color depth for this connection'), defvalue='24', values=[ { 'id': '8', 'text': '8' }, { 'id': '16', 'text': '16' }, { 'id': '24', 'text': '24' }, { 'id': '32', 'text': '32' }, ], tab=gui.DISPLAY_TAB) wallpaper = gui.CheckBoxField( label=_('Wallpaper/theme'), order=32, tooltip= _('If checked, the wallpaper and themes will be shown on machine (better user experience, more bandwidth)' ), tab=gui.DISPLAY_TAB) multimon = gui.CheckBoxField( label=_('Multiple monitors'), order=33, tooltip= _('If checked, all client monitors will be used for displaying (only works on windows clients)' ), tab=gui.DISPLAY_TAB) aero = gui.CheckBoxField( label=_('Allow Desk.Comp.'), order=34, tooltip=_('If checked, desktop composition will be allowed'), tab=gui.DISPLAY_TAB) smooth = gui.CheckBoxField( label=_('Font Smoothing'), order=35, tooltip=_('If checked, fonts smoothing will be allowed'), tab=gui.DISPLAY_TAB) showConnectionBar = gui.CheckBoxField( label=_('Connection Bar'), order=36, tooltip=_( 'If checked, connection bar will be shown (only on Windows clients)' ), tab=gui.DISPLAY_TAB, defvalue=gui.TRUE) multimedia = gui.CheckBoxField( label=_('Multimedia sync'), order=40, tooltip= _('If checked. Linux client will use multimedia parameter for xfreerdp' ), tab='Linux Client') alsa = gui.CheckBoxField( label=_('Use Alsa'), order=41, tooltip= _('If checked, Linux client will try to use ALSA, otherwise Pulse will be used' ), tab='Linux Client') redirectHome = gui.CheckBoxField( label=_('Redirect home folder'), order=42, tooltip=_( 'If checked, Linux client will try to redirect /home local folder' ), tab='Linux Client', defvalue=gui.FALSE) printerString = gui.TextField( label=_('Printer string'), order=43, tooltip= _('If printer is checked, the printer string used with xfreerdp client' ), tab='Linux Client') smartcardString = gui.TextField( label=_('Smartcard string'), order=44, tooltip= _('If smartcard is checked, the smartcard string used with xfreerdp client' ), tab='Linux Client') customParameters = gui.TextField( label=_('Custom parameters'), order=45, tooltip= _('If not empty, extra parameter to include for Linux Client (for example /usb:id,dev:054c:0268, or aything compatible with your xfreerdp client)' ), tab='Linux Client') def isAvailableFor(self, userService, ip): """ Checks if the transport is available for the requested destination ip Override this in yours transports """ logger.debug('Checking availability for {0}'.format(ip)) ready = self.cache.get(ip) if ready is None: # Check again for ready if self.testServer(userService, ip, '3389') is True: self.cache.put(ip, 'Y', READY_CACHE_TIMEOUT) return True else: self.cache.put(ip, 'N', READY_CACHE_TIMEOUT) return ready == 'Y' def processedUser(self, userService, userName): v = self.processUserPassword(userService, userName, '') return v['username'] def processUserPassword(self, service, user, password): username = user.getUsernameForAuth() if self.fixedName.value != '': username = self.fixedName.value proc = username.split('@') if len(proc) > 1: domain = proc[1] else: domain = '' username = proc[0] if self.fixedPassword.value != '': password = self.fixedPassword.value if self.fixedDomain.value != '': domain = self.fixedDomain.value if self.useEmptyCreds.isTrue(): username, password, domain = '', '', '' if self.withoutDomain.isTrue(): domain = '' if domain != '': # If has domain if '.' in domain: # Dotter domain form username = username + '@' + domain domain = '' else: # In case of a NETBIOS domain (not recomended), join it so processUserPassword can deal with it username = domain + '\\' + username domain = '' # Temporal "fix" to check if we do something on processUserPassword # Fix username/password acording to os manager username, password = service.processUserPassword(username, password) # Recover domain name if needed if '\\' in username: username, domain = username.split('\\') return { 'protocol': self.protocol, 'username': username, 'password': password, 'domain': domain } def getConnectionInfo(self, service, user, password): return self.processUserPassword(service, user, password) def getScript(self, scriptName, osName, params) -> Tuple[str, str, dict]: # Reads script scriptName = scriptName.format(osName) with open(os.path.join(os.path.dirname(__file__), scriptName)) as f: script = f.read() # Reads signature with open( os.path.join(os.path.dirname(__file__), scriptName + '.signature')) as f: signature = f.read() return script, signature, params
class WindowsOsManager(osmanagers.OSManager): typeName = _('Windows Basic OS Manager') typeType = 'WindowsManager' typeDescription = _( 'Os Manager to control windows machines without domain.') iconFile = 'wosmanager.png' servicesType = (serviceTypes.VDI, ) onLogout = gui.ChoiceField( label=_('Logout Action'), order=10, rdonly=True, tooltip=_('What to do when user logs out from service'), values=[ { 'id': 'keep', 'text': ugettext_lazy('Keep service assigned') }, { 'id': 'remove', 'text': ugettext_lazy('Remove service') }, { 'id': 'keep-always', 'text': ugettext_lazy('Keep service assigned even on new publication') }, ], defvalue='keep') idle = gui.NumericField( label=_("Max.Idle time"), length=4, defvalue=-1, rdonly=False, order=11, tooltip= _('Maximum idle time (in seconds) before session is automatically closed to the user (<= 0 means no max. idle time)' ), required=True) @staticmethod def validateLen(length): try: length = int(length) except Exception: raise osmanagers.OSManager.ValidationException( _('Length must be numeric!!')) if length > 6 or length < 1: raise osmanagers.OSManager.ValidationException( _('Length must be betwen 1 and 6')) return length def __setProcessUnusedMachines(self): self.processUnusedMachines = self._onLogout == 'remove' def __init__(self, environment, values): super(WindowsOsManager, self).__init__(environment, values) if values is not None: self._onLogout = values['onLogout'] self._idle = int(values['idle']) else: self._onLogout = '' self._idle = -1 self.__setProcessUnusedMachines() def isRemovableOnLogout(self, userService): ''' Says if a machine is removable on logout ''' if userService.in_use == False: if (self._onLogout == 'remove') or (not userService.isValidPublication() and self._onLogout == 'keep'): return True return False def release(self, service): pass def getName(self, service): """ gets name from deployed """ return service.getName() def infoVal(self, service): return 'rename:' + self.getName(service) def infoValue(self, service): return 'rename\r' + self.getName(service) def notifyIp(self, uid, service, data): si = service.getInstance() ip = '' # Notifies IP to deployed for p in data['ips']: if p[0].lower() == uid.lower(): si.setIp(p[1]) ip = p[1] break self.logKnownIp(service, ip) service.updateData(si) def doLog(self, service, data, origin=log.OSMANAGER): # Stores a log associated with this service try: msg, level = data.split('\t') try: level = int(level) except Exception: logger.debug('Do not understand level {}'.format(level)) level = log.INFO log.doLog(service, level, msg, origin) except Exception: logger.exception('WindowsOs Manager message log: ') log.doLog(service, log.ERROR, "do not understand {0}".format(data), origin) # default "ready received" does nothing def readyReceived(self, userService, data): pass def process(self, userService, msg, data, options=None): """ We understand this messages: * msg = info, data = None. Get information about name of machine (or domain, in derived WinDomainOsManager class) (old method) * msg = information, data = None. Get information about name of machine (or domain, in derived WinDomainOsManager class) (new method) * msg = logon, data = Username, Informs that the username has logged in inside the machine * msg = logoff, data = Username, Informs that the username has logged out of the machine * msg = ready, data = None, Informs machine ready to be used """ logger.info( "Invoked WindowsOsManager for {0} with params: {1},{2}".format( userService, msg, data)) if msg in ('ready', 'ip'): if not isinstance( data, dict ): # Old actors, previous to 2.5, convert it information.. data = { 'ips': [v.split('=') for v in data.split(',')], 'hostname': userService.friendly_name } # We get from storage the name for this userService. If no name, we try to assign a new one ret = "ok" notifyReady = False doRemove = False state = userService.os_state if msg == "info": ret = self.infoVal(userService) state = State.PREPARING elif msg == "information": ret = self.infoValue(userService) state = State.PREPARING elif msg == "log": self.doLog(userService, data, log.ACTOR) elif msg == "logon" or msg == 'login': if '\\' not in data: self.loggedIn(userService, data) userService.setInUse(True) # We get the userService logged hostname & ip and returns this ip, hostname = userService.getConnectionSource() deadLine = userService.deployed_service.getDeadline() if userService.getProperty('actor_version', '0.0.0') >= '2.0.0': ret = "{0}\t{1}\t{2}".format( ip, hostname, 0 if deadLine is None else deadLine) else: ret = "{0}\t{1}".format(ip, hostname) elif msg == "logoff" or msg == 'logout': self.loggedOut(userService, data) doRemove = self.isRemovableOnLogout(userService) elif msg == "ip": # This ocurss on main loop inside machine, so userService is usable state = State.USABLE self.notifyIp(userService.unique_id, userService, data) elif msg == "ready": self.toReady(userService) state = State.USABLE notifyReady = True self.notifyIp(userService.unique_id, userService, data) self.readyReceived(userService, data) userService.setOsState(state) # If notifyReady is not true, save state, let UserServiceManager do it for us else if doRemove is True: userService.release() else: if notifyReady is False: userService.save(update_fields=[ 'in_use', 'in_use_date', 'os_state', 'state', 'data' ]) else: logger.debug('Notifying ready') UserServiceManager.manager().notifyReadyFromOsManager( userService, '') logger.debug('Returning {} to {} message'.format(ret, msg)) if options is not None and options.get('scramble', True) is False: return ret return scrambleMsg(ret) def processUserPassword(self, service, username, password): if service.getProperty('sso_available') == '1': # Generate a ticket, store it and return username with no password domain = '' if '@' in username: username, domain = username.split('@') elif '\\' in username: username, domain = username.split('\\') creds = { 'username': username, 'password': password, 'domain': domain } ticket = TicketStore.create( creds, validator=None, validity=300) # , owner=SECURE_OWNER, secure=True) return ticket, '' else: return osmanagers.OSManager.processUserPassword( self, service, username, password) def processUnused(self, userService): """ This will be invoked for every assigned and unused user service that has been in this state at least 1/2 of Globalconfig.CHECK_UNUSED_TIME This function can update userService values. Normal operation will be remove machines if this state is not valid """ if self.isRemovableOnLogout(userService): userService.remove() def isPersistent(self): return self._onLogout == 'keep-always' def checkState(self, service): logger.debug('Checking state for service {0}'.format(service)) return State.RUNNING def maxIdle(self): """ On production environments, will return no idle for non removable machines """ if self._idle <= 0: # or (settings.DEBUG is False and self._onLogout != 'remove'): return None return self._idle def marshal(self): """ Serializes the os manager data so we can store it in database """ return '\t'.join(['v2', self._onLogout, str(self._idle)]).encode('utf8') def unmarshal(self, s): data = s.decode('utf8').split('\t') try: if data[0] == 'v1': self._onLogout = data[1] self._idle = -1 elif data[0] == 'v2': self._onLogout, self._idle = data[1], int(data[2]) except Exception: logger.exception( 'Exception unmarshalling. Some values left as default ones') self.__setProcessUnusedMachines() def valuesDict(self): return {'onLogout': self._onLogout, 'idle': self._idle}
class TSNXTransport(Transport): """ Provides access via NX to service. This transport can use an domain. If username processed by authenticator contains '@', it will split it and left-@-part will be username, and right password """ typeName = _('NX v3.5') typeType = 'TSNXTransport' typeDescription = _('NX protocol v3.5. Tunneled connection.') iconFile = 'nx.png' protocol = protocols.NX group = TUNNELED_GROUP 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)'), tab=gui.TUNNEL_TAB) 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)'), tab=gui.TUNNEL_TAB) useEmptyCreds = gui.CheckBoxField(label=_('Empty creds'), order=3, tooltip=_('If checked, the credentials used to connect will be emtpy'), tab=gui.CREDENTIALS_TAB) fixedName = gui.TextField(label=_('Username'), order=4, tooltip=_('If not empty, this username will be always used as credential'), tab=gui.CREDENTIALS_TAB) fixedPassword = gui.PasswordField(label=_('Password'), order=5, tooltip=_('If not empty, this password will be always used as credential'), tab=gui.CREDENTIALS_TAB) listenPort = gui.NumericField(label=_('Listening port'), length=5, order=6, tooltip=_('Listening port of NX (ssh) at client machine'), defvalue='22') connection = gui.ChoiceField(label=_('Connection'), order=7, tooltip=_('Connection speed for this transport (quality)'), values=[ {'id': 'modem', 'text': 'modem'}, {'id': 'isdn', 'text': 'isdn'}, {'id': 'adsl', 'text': 'adsl'}, {'id': 'wan', 'text': 'wan'}, {'id': 'lan', 'text': 'lan'}, ], tab=gui.PARAMETERS_TAB) session = gui.ChoiceField(label=_('Session'), order=8, tooltip=_('Desktop session'), values=[ {'id': 'gnome', 'text': 'gnome'}, {'id': 'kde', 'text': 'kde'}, {'id': 'cde', 'text': 'cde'}, ], tab=gui.PARAMETERS_TAB) cacheDisk = gui.ChoiceField(label=_('Disk Cache'), order=9, tooltip=_('Cache size en Mb stored at disk'), values=[ {'id': '0', 'text': '0 Mb'}, {'id': '32', 'text': '32 Mb'}, {'id': '64', 'text': '64 Mb'}, {'id': '128', 'text': '128 Mb'}, {'id': '256', 'text': '256 Mb'}, {'id': '512', 'text': '512 Mb'}, ], tab=gui.PARAMETERS_TAB) cacheMem = gui.ChoiceField(label=_('Memory Cache'), order=10, tooltip=_('Cache size en Mb kept at memory'), values=[ {'id': '4', 'text': '4 Mb'}, {'id': '8', 'text': '8 Mb'}, {'id': '16', 'text': '16 Mb'}, {'id': '32', 'text': '32 Mb'}, {'id': '64', 'text': '64 Mb'}, {'id': '128', 'text': '128 Mb'}, ], tab=gui.PARAMETERS_TAB) def __init__(self, environment, values=None): super(TSNXTransport, self).__init__(environment, values) if values is not None: if values['tunnelServer'].find(':') == -1: raise Transport.ValidationException(_('Must use HOST:PORT in Tunnel Server Field')) self._tunnelServer = values['tunnelServer'] self._tunnelCheckServer = values['tunnelCheckServer'] self._useEmptyCreds = gui.strToBool(values['useEmptyCreds']) self._fixedName = values['fixedName'] self._fixedPassword = values['fixedPassword'] self._listenPort = values['listenPort'] self._connection = values['connection'] self._session = values['session'] self._cacheDisk = values['cacheDisk'] self._cacheMem = values['cacheMem'] else: self._tunnelServer = '' self._tunnelCheckServer = '' self._useEmptyCreds = '' self._fixedName = '' self._fixedPassword = '' self._listenPort = '' self._connection = '' self._session = '' self._cacheDisk = '' self._cacheMem = '' def marshal(self): """ Serializes the transport data so we can store it in database """ return str.join('\t', ['v1', gui.boolToStr(self._useEmptyCreds), self._fixedName, self._fixedPassword, self._listenPort, self._connection, self._session, self._cacheDisk, self._cacheMem, self._tunnelServer, self._tunnelCheckServer]) def unmarshal(self, string): data = string.split('\t') if data[0] == 'v1': self._useEmptyCreds = gui.strToBool(data[1]) self._fixedName, self._fixedPassword, self._listenPort, self._connection, self._session, self._cacheDisk, self._cacheMem, self._tunnelServer, self._tunnelCheckServer = data[2:] def valuesDict(self): return { 'useEmptyCreds': gui.boolToStr(self._useEmptyCreds), 'fixedName': self._fixedName, 'fixedPassword': self._fixedPassword, 'listenPort': self._listenPort, 'connection': self._connection, 'session': self._session, 'cacheDisk': self._cacheDisk, 'cacheMem': self._cacheMem, 'tunnelServer': self._tunnelServer, 'tunnelCheckServer': self._tunnelCheckServer } def isAvailableFor(self, userService, ip): """ Checks if the transport is available for the requested destination ip Override this in yours transports """ logger.debug('Checking availability for {0}'.format(ip)) ready = self.cache.get(ip) if ready is None: # Check again for readyness if self.testServer(userService, ip, self._listenPort) is True: self.cache.put(ip, 'Y', READY_CACHE_TIMEOUT) return True else: self.cache.put(ip, 'N', READY_CACHE_TIMEOUT) return ready == 'Y' def getScript(self, script): with open(os.path.join(os.path.dirname(__file__), script)) as f: data = f.read() return data def getUDSTransportScript(self, userService, transport, ip, os, user, password, request): prefs = user.prefs('nx') username = user.getUsernameForAuth() proc = username.split('@') username = proc[0] if self._fixedName is not '': username = self._fixedName if self._fixedPassword is not '': password = self._fixedPassword if self._useEmptyCreds is True: username, password = '', '' tunpass = ''.join(random.choice(string.letters + string.digits) for _i in range(12)) tunuser = TicketStore.create(tunpass) sshServer = self._tunnelServer if ':' not in sshServer: sshServer += ':443' sshHost, sshPort = sshServer.split(':') logger.debug('Username generated: {0}, password: {1}'.format(tunuser, tunpass)) width, height = CommonPrefs.getWidthHeight(prefs) # Fix username/password acording to os manager username, password = userService.processUserPassword(username, password) m = { 'ip': ip, 'tunUser': tunuser, 'tunPass': tunpass, 'tunHost': sshHost, 'tunPort': sshPort, 'password': password, 'port': self._listenPort } r = NXFile(username=username, password=password, width=width, height=height) r.host = '{address}' r.port = '{port}' r.connection = self._connection r.desktop = self._session r.cachedisk = self._cacheDisk r.cachemem = self._cacheMem os = { OsDetector.Windows: 'windows', OsDetector.Linux: 'linux', OsDetector.Macintosh: 'macosx' }.get(os['OS']) if os is None: return super(self.__class__, self).getUDSTransportScript(userService, transport, ip, os, user, password, request) return self.getScript('scripts/{}/tunnel.py'.format(os)).format( r=r, m=DictAsObj(m), )
class LinuxOsManager(osmanagers.OSManager): typeName = _('Linux OS Manager') typeType = 'LinuxManager' typeDescription = _('Os Manager to control Linux virtual machines') iconFile = 'losmanager.png' servicesType = (serviceTypes.VDI, ) onLogout = gui.ChoiceField( label=_('Logout Action'), order=10, rdonly=True, tooltip=_('What to do when user logs out from service'), values=[ { 'id': 'keep', 'text': ugettext_lazy('Keep service assigned') }, { 'id': 'remove', 'text': ugettext_lazy('Remove service') }, { 'id': 'keep-always', 'text': ugettext_lazy('Keep service assigned even on new publication') }, ], defvalue='keep') idle = gui.NumericField( label=_("Max.Idle time"), length=4, defvalue=-1, rdonly=False, order=11, tooltip= _('Maximum idle time (in seconds) before session is automatically closed to the user (<= 0 means no max idle time).' ), required=True) def __setProcessUnusedMachines(self): self.processUnusedMachines = self._onLogout == 'remove' def __init__(self, environment, values): super(LinuxOsManager, self).__init__(environment, values) if values is not None: self._onLogout = values['onLogout'] self._idle = int(values['idle']) else: self._onLogout = '' self._idle = -1 self.__setProcessUnusedMachines() def release(self, service): pass def isRemovableOnLogout(self, userService): ''' Says if a machine is removable on logout ''' if userService.in_use == False: if (self._onLogout == 'remove') or (not userService.isValidPublication() and self._onLogout == 'keep'): return True return False def getName(self, service): """ gets name from deployed """ return service.getName() def infoVal(self, service): return 'rename:' + self.getName(service) def infoValue(self, service): return 'rename\r' + self.getName(service) def notifyIp(self, uid, service, data): si = service.getInstance() ip = '' # Notifies IP to deployed for p in data['ips']: if p[0].lower() == uid.lower(): si.setIp(p[1]) ip = p[1] break self.logKnownIp(service, ip) service.updateData(si) def doLog(self, service, data, origin=log.OSMANAGER): # Stores a log associated with this service try: msg, level = data.split('\t') try: level = int(level) except Exception: logger.debug('Do not understand level {}'.format(level)) level = log.INFO log.doLog(service, level, msg, origin) except Exception: log.doLog(service, log.ERROR, "do not understand {0}".format(data), origin) def process(self, userService, msg, data, options=None): """ We understand this messages: * msg = info, data = None. Get information about name of machine (or domain, in derived WinDomainOsManager class), old method * msg = information, data = None. Get information about name of machine (or domain, in derived WinDomainOsManager class), new method * msg = logon, data = Username, Informs that the username has logged in inside the machine * msg = logoff, data = Username, Informs that the username has logged out of the machine * msg = ready, data = None, Informs machine ready to be used """ logger.info( "Invoked LinuxOsManager for {0} with params: {1},{2}".format( userService, msg, data)) # We get from storage the name for this userService. If no name, we try to assign a new one ret = "ok" notifyReady = False doRemove = False state = userService.os_state if msg in ('ready', 'ip'): if not isinstance( data, dict ): # Old actors, previous to 2.5, convert it information.. data = { 'ips': [v.split('=') for v in data.split(',')], 'hostname': userService.friendly_name } # Old "info" state, will be removed in a near future if msg == "info": ret = self.infoVal(userService) state = State.PREPARING elif msg == "information": ret = self.infoValue(userService) state = State.PREPARING elif msg == "log": self.doLog(userService, data, log.ACTOR) elif msg == "login": self.loggedIn(userService, data, False) ip, hostname = userService.getConnectionSource() deadLine = userService.deployed_service.getDeadline() ret = "{0}\t{1}\t{2}".format(ip, hostname, 0 if deadLine is None else deadLine) elif msg == "logout": self.loggedOut(userService, data, False) doRemove = self.isRemovableOnLogout(userService) elif msg == "ip": # This ocurss on main loop inside machine, so userService is usable state = State.USABLE self.notifyIp(userService.unique_id, userService, data) elif msg == "ready": self.toReady(userService) state = State.USABLE notifyReady = True self.notifyIp(userService.unique_id, userService, data) userService.setOsState(state) # If notifyReady is not true, save state, let UserServiceManager do it for us else if doRemove is True: userService.release() else: if notifyReady is False: userService.save() else: UserServiceManager.manager().notifyReadyFromOsManager( userService, '') logger.debug('Returning {0}'.format(ret)) return ret def processUnused(self, userService): """ This will be invoked for every assigned and unused user service that has been in this state at least 1/2 of Globalconfig.CHECK_UNUSED_TIME This function can update userService values. Normal operation will be remove machines if this state is not valid """ if self.isRemovableOnLogout(userService): userService.remove() def isPersistent(self): return self._onLogout == 'keep-always' def checkState(self, service): logger.debug('Checking state for service {0}'.format(service)) return State.RUNNING def maxIdle(self): """ On production environments, will return no idle for non removable machines """ if self._idle <= 0: # or (settings.DEBUG is False and self._onLogout != 'remove'): return None return self._idle def marshal(self): """ Serializes the os manager data so we can store it in database """ return '\t'.join(['v2', self._onLogout, six.text_type(self._idle)]).encode('utf8') def unmarshal(self, s): data = s.decode('utf8').split('\t') if data[0] == 'v1': self._onLogout = data[1] self._idle = -1 elif data[0] == 'v2': self._onLogout, self._idle = data[1], int(data[2]) self.__setProcessUnusedMachines() def valuesDict(self): return {'onLogout': self._onLogout, 'idle': self._idle}
class TSNXTransport(Transport): ''' Provides access via RDP to service. This transport can use an domain. If username processed by authenticator contains '@', it will split it and left-@-part will be username, and right password ''' typeName = _('NX Transport (tunneled)') typeType = 'TSNXTransport' typeDescription = _('NX Transport for tunneled connection') iconFile = 'nx.png' needsJava = True # If this transport needs java for rendering supportedOss = ['Windows', 'Macintosh', 'Linux'] protocol = protocols.NX 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 = gui.CheckBoxField(label=_('Empty creds'), order=3, tooltip=_('If checked, the credentials used to connect will be emtpy')) fixedName = gui.TextField(label=_('Username'), order=4, tooltip=_('If not empty, this username will be always used as credential')) fixedPassword = gui.PasswordField(label=_('Password'), order=5, tooltip=_('If not empty, this password will be always used as credential')) listenPort = gui.NumericField(label=_('Listening port'), length=5, order=6, tooltip=_('Listening port of NX (ssh) at client machine'), defvalue='22') connection = gui.ChoiceField(label=_('Connection'), order=7, tooltip=_('Connection speed for this transport (quality)'), values=[ {'id': 'modem', 'text': 'modem'}, {'id': 'isdn', 'text': 'isdn'}, {'id': 'adsl', 'text': 'adsl'}, {'id': 'wan', 'text': 'wan'}, {'id': 'lan', 'text': 'lan'}, ]) session = gui.ChoiceField(label=_('Session'), order=8, tooltip=_('Desktop session'), values=[ {'id': 'gnome', 'text': 'gnome'}, {'id': 'kde', 'text': 'kde'}, {'id': 'cde', 'text': 'cde'}, ]) cacheDisk = gui.ChoiceField(label=_('Disk Cache'), order=9, tooltip=_('Cache size en Mb stored at disk'), values=[ {'id': '0', 'text': '0 Mb'}, {'id': '32', 'text': '32 Mb'}, {'id': '64', 'text': '64 Mb'}, {'id': '128', 'text': '128 Mb'}, {'id': '256', 'text': '256 Mb'}, {'id': '512', 'text': '512 Mb'}, ]) cacheMem = gui.ChoiceField(label=_('Memory Cache'), order=10, tooltip=_('Cache size en Mb kept at memory'), values=[ {'id': '4', 'text': '4 Mb'}, {'id': '8', 'text': '8 Mb'}, {'id': '16', 'text': '16 Mb'}, {'id': '32', 'text': '32 Mb'}, {'id': '64', 'text': '64 Mb'}, {'id': '128', 'text': '128 Mb'}, ]) def __init__(self, environment, values=None): super(TSNXTransport, self).__init__(environment, values) if values != None: if values['tunnelServer'].find(':') == -1: raise Transport.ValidationException(_('Must use HOST:PORT in Tunnel Server Field')) self._tunnelServer = values['tunnelServer'] self._tunnelCheckServer = values['tunnelCheckServer'] self._useEmptyCreds = gui.strToBool(values['useEmptyCreds']) self._fixedName = values['fixedName'] self._fixedPassword = values['fixedPassword'] self._listenPort = values['listenPort'] self._connection = values['connection'] self._session = values['session'] self._cacheDisk = values['cacheDisk'] self._cacheMem = values['cacheMem'] else: self._tunnelServer = '' self._tunnelCheckServer = '' self._useEmptyCreds = '' self._fixedName = '' self._fixedPassword = '' self._listenPort = '' self._connection = '' self._session = '' self._cacheDisk = '' self._cacheMem = '' def marshal(self): ''' Serializes the transport data so we can store it in database ''' return str.join('\t', [ 'v1', gui.boolToStr(self._useEmptyCreds), self._fixedName, self._fixedPassword, self._listenPort, self._connection, self._session, self._cacheDisk, self._cacheMem, self._tunnelServer, self._tunnelCheckServer ]) def unmarshal(self, string): data = string.split('\t') if data[0] == 'v1': self._useEmptyCreds = gui.strToBool(data[1]) self._fixedName, self._fixedPassword, self._listenPort, self._connection, self._session, self._cacheDisk, self._cacheMem, self._tunnelServer, self._tunnelCheckServer = data[2:] def valuesDict(self): return { 'useEmptyCreds': gui.boolToStr(self._useEmptyCreds), 'fixedName': self._fixedName, 'fixedPassword': self._fixedPassword, 'listenPort': self._listenPort, 'connection': self._connection, 'session': self._session, 'cacheDisk': self._cacheDisk, 'cacheMem': self._cacheMem, 'tunnelServer': self._tunnelServer, 'tunnelCheckServer': self._tunnelCheckServer } def isAvailableFor(self, ip): ''' Checks if the transport is available for the requested destination ip Override this in yours transports ''' logger.debug('Checking availability for {0}'.format(ip)) ready = self.cache().get(ip) if ready is None: # Check again for readyness if connection.testServer(ip, self._listenPort) is True: self.cache().put(ip, 'Y', READY_CACHE_TIMEOUT) return True else: self.cache().put(ip, 'N', READY_CACHE_TIMEOUT) return ready == 'Y' def renderForHtml(self, userService, transport, ip, os, user, password): prefs = user.prefs('nx') username = user.getUsernameForAuth() proc = username.split('@') username = proc[0] if self._fixedName is not '': username = self._fixedName if self._fixedPassword is not '': password = self._fixedPassword if self._useEmptyCreds is True: username, password = '', '' width, height = CommonPrefs.getWidthHeight(prefs) cache = Cache('pam') tunuser = ''.join(random.choice(string.letters + string.digits) for _i in range(12)) + ("%f" % time.time()).split('.')[1] tunpass = ''.join(random.choice(string.letters + string.digits) for _i in range(12)) cache.put(tunuser, tunpass, 60 * 10) # Credential valid for ten minutes, and for 1 use only sshHost, sshPort = self._tunnelServer.split(':') logger.debug('Username generated: {0}, password: {1}'.format(tunuser, tunpass)) tun = "{0} {1} {2} {3} {4} {5} {6}".format(tunuser, tunpass, sshHost, sshPort, ip, self._listenPort, '9') # Extra data extra = { 'width': width, 'height': height, 'connection': self._connection, 'session': self._session, 'cacheDisk': self._cacheDisk, 'cacheMem': self._cacheMem, 'tun': tun } # Fix username/password acording to os manager username, password = userService.processUserPassword(username, password) return generateHtmlForNX(self, userService.uuid, transport.uuid, os, username, password, extra) def getHtmlComponent(self, theId, os, componentId): # We use helper to keep this clean return getHtmlComponent(self.__module__, componentId)
class HTML5RDPTransport(Transport): """ Provides access via RDP to service. This transport can use an domain. If username processed by authenticator contains '@', it will split it and left-@-part will be username, and right password """ typeName = _('HTML5 RDP') typeType = 'HTML5RDPTransport' typeDescription = _('RDP protocol using HTML5 client') iconFile = 'html5.png' ownLink = True supportedOss = OsDetector.allOss protocol = protocols.RDP group = TUNNELED_GROUP guacamoleServer = gui.TextField( label=_('Tunnel Server'), order=1, tooltip= _('Host of the tunnel server (use http/https & port if needed) as accesible from users' ), defvalue='https://', length=64, required=True, tab=gui.TUNNEL_TAB) useEmptyCreds = gui.CheckBoxField( label=_('Empty creds'), order=2, tooltip=_('If checked, the credentials used to connect will be emtpy'), tab=gui.CREDENTIALS_TAB) fixedName = gui.TextField( label=_('Username'), order=3, tooltip=_( 'If not empty, this username will be always used as credential'), tab=gui.CREDENTIALS_TAB) fixedPassword = gui.PasswordField( label=_('Password'), order=4, tooltip=_( 'If not empty, this password will be always used as credential'), tab=gui.CREDENTIALS_TAB) withoutDomain = gui.CheckBoxField( label=_('Without Domain'), order=5, tooltip= _('If checked, the domain part will always be emptied (to connecto to xrdp for example is needed)' ), tab=gui.CREDENTIALS_TAB) fixedDomain = gui.TextField( label=_('Domain'), order=6, tooltip= _('If not empty, this domain will be always used as credential (used as DOMAIN\\user)' ), tab=gui.CREDENTIALS_TAB) wallpaper = gui.CheckBoxField( label=_('Show wallpaper'), order=20, tooltip= _('If checked, the wallpaper and themes will be shown on machine (better user experience, more bandwidth)' ), tab=gui.PARAMETERS_TAB) desktopComp = gui.CheckBoxField( label=_('Allow Desk.Comp.'), order=22, tooltip=_('If checked, desktop composition will be allowed'), tab=gui.PARAMETERS_TAB) smooth = gui.CheckBoxField( label=_('Font Smoothing'), order=23, tooltip=_( 'If checked, fonts smoothing will be allowed (windows clients only)' ), tab=gui.PARAMETERS_TAB) enableAudio = gui.CheckBoxField( label=_('Enable Audio'), order=24, tooltip= _('If checked, the audio will be redirected to client (if client browser supports it)' ), tab=gui.PARAMETERS_TAB) enablePrinting = gui.CheckBoxField( label=_('Enable Printing'), order=25, tooltip= _('If checked, the printing will be redirected to client (if client browser supports it)' ), tab=gui.PARAMETERS_TAB) enableFileSharing = gui.CheckBoxField( label=_('Enable File Sharing'), order=8, tooltip= _('If checked, the user will be able to upload/download files (if client browser supports it)' ), tab=gui.PARAMETERS_TAB) serverLayout = gui.ChoiceField( order=26, label=_('Layout'), tooltip=_('Keyboards Layout of server'), required=True, values=[ gui.choiceItem('-', 'default'), gui.choiceItem('en-us-qwerty', _('English (US) keyboard')), gui.choiceItem('de-de-qwertz', _('German keyboard (qwertz)')), gui.choiceItem('fr-fr-azerty', _('French keyboard (azerty)')), gui.choiceItem('it-it-qwerty', _('Italian keyboard')), gui.choiceItem('sv-se-qwerty', _('Swedish keyboard')), gui.choiceItem('failsafe', _('Failsafe')), ], defvalue='-', tab=gui.PARAMETERS_TAB) security = gui.ChoiceField( order=27, label=_('Security'), tooltip=_('Connection security mode for Guacamole RDP connection'), required=True, values=[ gui.choiceItem( 'any', _('Any (Allow the server to choose the type of auth)')), gui.choiceItem( 'rdp', _('RDP (Standard RDP encryption. Should be supported by all servers)' )), gui.choiceItem( 'nla', _('NLA (Network Layer authentication. Requires VALID username&password, or connection will fail)' )), gui.choiceItem('tls', _('TLS (Transport Security Layer encryption)')), ], defvalue='rdp', tab=gui.PARAMETERS_TAB) ticketValidity = gui.NumericField( length=3, label=_('Ticket Validity'), defvalue='60', order=90, tooltip= _('Allowed time, in seconds, for HTML5 client to reload data from UDS Broker. The default value of 60 is recommended.' ), required=True, minValue=60, tab=gui.ADVANCED_TAB) def initialize(self, values): if values is None: return self.guacamoleServer.value = self.guacamoleServer.value.strip() if self.guacamoleServer.value[0:4] != 'http': raise Transport.ValidationException( _('The server must be http or https')) if self.useEmptyCreds.isTrue() and self.security.value != 'rdp': raise Transport.ValidationException( _('Empty credentials (on Credentials tab) is only allowed with Security level (on Parameters tab) set to "RDP"' )) # Same check as normal RDP transport def isAvailableFor(self, userService, ip): """ Checks if the transport is available for the requested destination ip Override this in yours transports """ logger.debug('Checking availability for {0}'.format(ip)) ready = self.cache.get(ip) if ready is None: # Check again for readyness if self.testServer(userService, ip, '3389') is True: self.cache.put(ip, 'Y', READY_CACHE_TIMEOUT) return True else: self.cache.put(ip, 'N', READY_CACHE_TIMEOUT) return ready == 'Y' def processedUser(self, userService, userName): v = self.processUserPassword(userService, userName, '') return v['username'] def processUserPassword(self, service, user, password): username = user.getUsernameForAuth() if self.fixedName.value != '': username = self.fixedName.value proc = username.split('@') if len(proc) > 1: domain = proc[1] else: domain = '' username = proc[0] if self.fixedPassword.value != '': password = self.fixedPassword.value if self.fixedDomain.value != '': domain = self.fixedDomain.value if self.useEmptyCreds.isTrue(): username, password, domain = '', '', '' if self.withoutDomain.isTrue(): domain = '' if '.' in domain: # Dotter domain form username = username + '@' + domain domain = '' # Fix username/password acording to os manager username, password = service.processUserPassword(username, password) return { 'protocol': self.protocol, 'username': username, 'password': password, 'domain': domain } def getLink(self, userService, transport, ip, os, user, password, request): ci = self.processUserPassword(userService, user, password) username, password, domain = ci['username'], ci['password'], ci[ 'domain'] if domain != '': username = domain + '\\' + username scrambler = cryptoManager().randomString(32) passwordCrypted = cryptoManager().symCrypt(password, scrambler) # Build params dict params = { 'protocol': 'rdp', 'hostname': ip, 'username': username, 'password': passwordCrypted, 'ignore-cert': 'true', 'security': self.security.value, 'drive-path': '/share/{}'.format(user.uuid), 'create-drive-path': 'true' } if self.enableFileSharing.isTrue(): params['enable-drive'] = 'true' if self.serverLayout.value != '-': params['server-layout'] = self.serverLayout.value if self.enableAudio.isTrue() is False: params['disable-audio'] = 'true' if self.enablePrinting.isTrue() is True: params['enable-printing'] = 'true' if self.wallpaper.isTrue() is True: params['enable-wallpaper'] = 'true' if self.desktopComp.isTrue() is True: params['enable-desktop-composition'] = 'true' if self.smooth.isTrue() is True: params['enable-font-smoothing'] = 'true' logger.debug('RDP Params: {0}'.format(params)) ticket = TicketStore.create(params, validity=self.ticketValidity.num()) return HttpResponseRedirect("{}/transport/?{}.{}&{}".format( self.guacamoleServer.value, ticket, scrambler, request.build_absolute_uri(reverse('Index'))))
class UsageByPool(StatsReport): filename = 'pools_usage.pdf' name = _('Pools usage by users') # Report name description = _('Pools usage by user report') # Report description uuid = '38ec12dc-beaf-11e5-bd0a-10feed05884b' # Input fields pool = gui.ChoiceField(order=1, label=_('Pool'), tooltip=_('Pool for report'), required=True) startDate = gui.DateField(order=2, label=_('Starting date'), tooltip=_('starting date for report'), defvalue=datetime.date.min, required=True) endDate = gui.DateField(order=3, label=_('Finish date'), tooltip=_('finish date for report'), defvalue=datetime.date.max, required=True) def initialize(self, values): pass def initGui(self): logger.debug('Initializing gui') vals = [ gui.choiceItem(v.uuid, v.name) for v in ServicePool.objects.all() ] self.pool.setValues(vals) def getData(self): # Generate the sampling intervals and get dataUsers from db start = self.startDate.stamp() end = self.endDate.stamp() logger.debug(self.pool.value) pool = ServicePool.objects.get(uuid=self.pool.value) items = events.statsManager().getEvents( events.OT_DEPLOYED, (events.ET_LOGIN, events.ET_LOGOUT), owner_id=pool.id, since=start, to=end).order_by('stamp') logins = {} data = [] for i in items: # if '\\' in i.fld1: # continue if i.event_type == events.ET_LOGIN: logins[i.fld4] = i.stamp else: if i.fld4 in logins: stamp = logins[i.fld4] del logins[i.fld4] total = i.stamp - stamp data.append({ 'name': i.fld4, 'date': datetime.datetime.fromtimestamp(stamp), 'time': total }) logger.debug('data') return data, pool.name def generate(self): items, poolName = self.getData() output = StringIO.StringIO() report = UsersReport(queryset=items) report.title = _('Users usage list for {}').format(poolName) report.generate_by(PDFGenerator, filename=output) return output.getvalue()
class NXTransport(Transport): """ Provides access via NX to service. This transport can use an domain. If username processed by authenticator contains '@', it will split it and left-@-part will be username, and right password """ typeName = _('NX v3.5') typeType = 'NXTransport' typeDescription = _('NX Protocol v3.5. Direct connection.') iconFile = 'nx.png' protocol = protocols.NX useEmptyCreds = gui.CheckBoxField( label=_('Empty creds'), order=1, tooltip=_('If checked, the credentials used to connect will be emtpy'), tab=gui.CREDENTIALS_TAB) fixedName = gui.TextField( label=_('Username'), order=2, tooltip=_( 'If not empty, this username will be always used as credential'), tab=gui.CREDENTIALS_TAB) fixedPassword = gui.PasswordField( label=_('Password'), order=3, tooltip=_( 'If not empty, this password will be always used as credential'), tab=gui.CREDENTIALS_TAB) listenPort = gui.NumericField( label=_('Listening port'), length=5, order=4, tooltip=_('Listening port of NX (ssh) at client machine'), defvalue='22') connection = gui.ChoiceField( label=_('Connection'), order=6, tooltip=_('Connection speed for this transport (quality)'), values=[{ 'id': 'modem', 'text': 'modem' }, { 'id': 'isdn', 'text': 'isdn' }, { 'id': 'adsl', 'text': 'adsl' }, { 'id': 'wan', 'text': 'wan' }, { 'id': 'lan', 'text': 'lan' }], tab=gui.PARAMETERS_TAB) session = gui.ChoiceField(label=_('Session'), order=7, tooltip=_('Desktop session'), values=[ { 'id': 'gnome', 'text': 'gnome' }, { 'id': 'kde', 'text': 'kde' }, { 'id': 'cde', 'text': 'cde' }, ], tab=gui.PARAMETERS_TAB) cacheDisk = gui.ChoiceField(label=_('Disk Cache'), order=8, tooltip=_('Cache size en Mb stored at disk'), values=[ { 'id': '0', 'text': '0 Mb' }, { 'id': '32', 'text': '32 Mb' }, { 'id': '64', 'text': '64 Mb' }, { 'id': '128', 'text': '128 Mb' }, { 'id': '256', 'text': '256 Mb' }, { 'id': '512', 'text': '512 Mb' }, ], tab=gui.PARAMETERS_TAB) cacheMem = gui.ChoiceField(label=_('Memory Cache'), order=9, tooltip=_('Cache size en Mb kept at memory'), values=[ { 'id': '4', 'text': '4 Mb' }, { 'id': '8', 'text': '8 Mb' }, { 'id': '16', 'text': '16 Mb' }, { 'id': '32', 'text': '32 Mb' }, { 'id': '64', 'text': '64 Mb' }, { 'id': '128', 'text': '128 Mb' }, ], tab=gui.PARAMETERS_TAB) def __init__(self, environment, values=None): super(NXTransport, self).__init__(environment, values) if values is not None: self._useEmptyCreds = gui.strToBool(values['useEmptyCreds']) self._fixedName = values['fixedName'] self._fixedPassword = values['fixedPassword'] self._listenPort = values['listenPort'] self._connection = values['connection'] self._session = values['session'] self._cacheDisk = values['cacheDisk'] self._cacheMem = values['cacheMem'] else: self._useEmptyCreds = '' self._fixedName = '' self._fixedPassword = '' self._listenPort = '' self._connection = '' self._session = '' self._cacheDisk = '' self._cacheMem = '' def marshal(self): """ Serializes the transport data so we can store it in database """ return str.join('\t', [ 'v1', gui.boolToStr(self._useEmptyCreds), self._fixedName, self._fixedPassword, self._listenPort, self._connection, self._session, self._cacheDisk, self._cacheMem ]).encode('utf8') def unmarshal(self, val): data = val.decode('utf8').split('\t') if data[0] == 'v1': self._useEmptyCreds = gui.strToBool(data[1]) self._fixedName, self._fixedPassword, self._listenPort, self._connection, self._session, self._cacheDisk, self._cacheMem = data[ 2:] def valuesDict(self): return { 'useEmptyCreds': gui.boolToStr(self._useEmptyCreds), 'fixedName': self._fixedName, 'fixedPassword': self._fixedPassword, 'listenPort': self._listenPort, 'connection': self._connection, 'session': self._session, 'cacheDisk': self._cacheDisk, 'cacheMem': self._cacheMem } def isAvailableFor(self, userService, ip): """ Checks if the transport is available for the requested destination ip Override this in yours transports """ logger.debug('Checking availability for {0}'.format(ip)) ready = self.cache.get(ip) if ready is None: # Check again for readyness if self.testServer(userService, ip, self._listenPort) is True: self.cache.put(ip, 'Y', READY_CACHE_TIMEOUT) return True else: self.cache.put(ip, 'N', READY_CACHE_TIMEOUT) return ready == 'Y' def getScript(self, script): with open(os.path.join(os.path.dirname(__file__), script)) as f: data = f.read() return data def getUDSTransportScript(self, userService, transport, ip, os, user, password, request): prefs = user.prefs('nx') username = user.getUsernameForAuth() proc = username.split('@') username = proc[0] if self._fixedName is not '': username = self._fixedName if self._fixedPassword is not '': password = self._fixedPassword if self._useEmptyCreds is True: username, password = '', '' # We have the credentials right now, let os manager width, height = CommonPrefs.getWidthHeight(prefs) # Fix username/password acording to os manager username, password = userService.processUserPassword( username, password) r = NXFile(username=username, password=password, width=width, height=height) r.host = ip r.port = self._listenPort r.connection = self._connection r.desktop = self._session r.cachedisk = self._cacheDisk r.cachemem = self._cacheMem os = { OsDetector.Windows: 'windows', OsDetector.Linux: 'linux', OsDetector.Macintosh: 'macosx' }.get(os['OS']) if os is None: return super(self.__class__, self).getUDSTransportScript(userService, transport, ip, os, user, password, request) return self.getScript('scripts/{}/direct.py'.format(os)).format(r=r)
class UsageSummaryByPool(StatsReport): filename = 'pools_usage.pdf' name = _('Summary of pools usage') # Report name description = _('Generates a report with the summary of a pool usage' ) # Report description uuid = '202c6438-30a8-11e7-80e4-77c1e4cb9e09' # Input fields pool = gui.ChoiceField(order=1, label=_('Pool'), tooltip=_('Pool for report'), required=True) startDate = gui.DateField(order=2, label=_('Starting date'), tooltip=_('starting date for report'), defvalue=datetime.date.min, required=True) endDate = gui.DateField(order=3, label=_('Finish date'), tooltip=_('finish date for report'), defvalue=datetime.date.max, required=True) def initialize(self, values): pass def initGui(self): logger.debug('Initializing gui') vals = [ gui.choiceItem(v.uuid, v.name) for v in ServicePool.objects.all() ] self.pool.setValues(vals) def getPoolData(self, pool): start = self.startDate.stamp() end = self.endDate.stamp() logger.debug(self.pool.value) items = events.statsManager().getEvents( events.OT_DEPLOYED, (events.ET_LOGIN, events.ET_LOGOUT), owner_id=pool.id, since=start, to=end).order_by('stamp') logins = {} users = {} for i in items: # if '\\' in i.fld1: # continue username = i.fld4 if i.event_type == events.ET_LOGIN: logins[username] = i.stamp else: if username in logins: stamp = logins[username] del logins[username] total = i.stamp - stamp if username not in users: users[username] = {'sessions': 0, 'time': 0} users[username]['sessions'] += 1 users[username]['time'] += total # data.append({ # 'name': i.fld4, # 'date': datetime.datetime.fromtimestamp(stamp), # 'time': total # }) # Extract different number of users data = [] for k, v in users.items(): data.append({ 'user': k, 'sessions': v['sessions'], 'hours': '{:.2f}'.format(float(v['time']) / 3600), 'average': '{:.2f}'.format(float(v['time']) / 3600 / v['sessions']) }) return data, pool.name def getData(self): return self.getPoolData(ServicePool.objects.get(uuid=self.pool.value)) def generate(self): items, poolName = self.getData() return self.templateAsPDF( 'uds/reports/stats/pool-usage-summary.html', dct={ 'data': items, 'pool': poolName, 'beginning': self.startDate.date(), 'ending': self.endDate.date(), }, header=ugettext('Users usage list for {}').format(poolName), water=ugettext('UDS Report of users in {}').format(poolName))
class WindowsOsManager(osmanagers.OSManager): typeName = _('Windows Basic OS Manager') typeType = 'WindowsManager' typeDescription = _( 'Os Manager to control windows machines without domain. (Basically renames machine)' ) iconFile = 'wosmanager.png' onLogout = gui.ChoiceField( label=_('On Logout'), order=10, rdonly=True, tooltip=_('What to do when user logs out from service'), values=[{ 'id': 'keep', 'text': _('Keep service assigned') }, { 'id': 'remove', 'text': _('Remove service') }], defvalue='keep') idle = gui.NumericField( label=_("Max.Idle time"), length=4, defvalue=-1, rdonly=False, order=11, tooltip= _('Maximum idle time (in seconds) before session is automaticatlly closed to the user (<= 0 means no max. idle time)' ), required=True) @staticmethod def validateLen(length): try: length = int(length) except Exception: raise osmanagers.OSManager.ValidationException( _('Length must be numeric!!')) if length > 6 or length < 1: raise osmanagers.OSManager.ValidationException( _('Length must be betwen 1 and 6')) return length def __setProcessUnusedMachines(self): self.processUnusedMachines = self._onLogout == 'remove' def __init__(self, environment, values): super(WindowsOsManager, self).__init__(environment, values) if values is not None: self._onLogout = values['onLogout'] self._idle = int(values['idle']) else: self._onLogout = '' self._idle = -1 self.__setProcessUnusedMachines() def release(self, service): pass def getName(self, service): ''' gets name from deployed ''' return service.getName() def infoVal(self, service): return 'rename:' + self.getName(service) def infoValue(self, service): return 'rename\r' + self.getName(service) def notifyIp(self, uid, service, data): si = service.getInstance() ip = '' # Notifies IP to deployed pairs = data.split(',') for p in pairs: key, val = p.split('=') if key.lower() == uid.lower(): si.setIp(val) ip = val break self.logKnownIp(service, ip) service.updateData(si) def doLog(self, service, data, origin=log.OSMANAGER): # Stores a log associated with this service try: msg, level = data.split('\t') try: level = int(level) except Exception: logger.debug('Do not understand level {}'.format(level)) level = log.INFO log.doLog(service, level, msg, origin) except Exception: logger.exception('LinuxOs Manager message log: ') log.doLog(service, log.ERROR, "do not understand {0}".format(data), origin) def process(self, service, msg, data, options): ''' We understand this messages: * msg = info, data = None. Get information about name of machine (or domain, in derived WinDomainOsManager class) (old method) * msg = information, data = None. Get information about name of machine (or domain, in derived WinDomainOsManager class) (new method) * msg = logon, data = Username, Informs that the username has logged in inside the machine * msg = logoff, data = Username, Informs that the username has logged out of the machine * msg = ready, data = None, Informs machine ready to be used ''' logger.info( "Invoked WindowsOsManager for {0} with params: {1},{2}".format( service, msg, data)) # We get from storage the name for this service. If no name, we try to assign a new one ret = "ok" notifyReady = False doRemove = False state = service.os_state if msg == "info": ret = self.infoVal(service) state = State.PREPARING elif msg == "information": ret = self.infoValue(service) state = State.PREPARING elif msg == "log": self.doLog(service, data, log.ACTOR) elif msg == "logon" or msg == 'login': if '\\' not in data: self.loggedIn(service, data, False) service.setInUse(True) # We get the service logged hostname & ip and returns this ip, hostname = service.getConnectionSource() ret = "{0}\t{1}".format(ip, hostname) elif msg == "logoff" or msg == 'logout': self.loggedOut(service, data, False) if self._onLogout == 'remove': doRemove = True elif msg == "ip": # This ocurss on main loop inside machine, so service is usable state = State.USABLE self.notifyIp(service.unique_id, service, data) elif msg == "ready": state = State.USABLE notifyReady = True self.notifyIp(service.unique_id, service, data) service.setOsState(state) # If notifyReady is not true, save state, let UserServiceManager do it for us else if doRemove is True: service.remove() else: if notifyReady is False: service.save() else: logger.debug('Notifying ready') UserServiceManager.manager().notifyReadyFromOsManager( service, '') logger.debug('Returning {} to {} message'.format(ret, msg)) if options is not None and options.get('scramble', True) is False: return ret return scrambleMsg(ret) def processUnused(self, userService): ''' This will be invoked for every assigned and unused user service that has been in this state at least 1/2 of Globalconfig.CHECK_UNUSED_TIME This function can update userService values. Normal operation will be remove machines if this state is not valid ''' if self._onLogout == 'remove': userService.remove() def checkState(self, service): logger.debug('Checking state for service {0}'.format(service)) return State.RUNNING def maxIdle(self): ''' On production environments, will return no idle for non removable machines ''' if self._idle <= 0 or (settings.DEBUG is False and self._onLogout != 'remove'): return None return self._idle def marshal(self): ''' Serializes the os manager data so we can store it in database ''' return '\t'.join(['v2', self._onLogout, six.text_type(self._idle)]) def unmarshal(self, s): data = s.split('\t') try: if data[0] == 'v1': self._onLogout = data[1] self._idle = -1 elif data[0] == 'v2': self._onLogout, self._idle = data[1], int(data[2]) except Exception: logger.exception( 'Exception unmarshalling. Some values left as default ones') self.__setProcessUnusedMachines() def valuesDict(self): return {'onLogout': self._onLogout, 'idle': self._idle}
class X2GOTransport(Transport): ''' Provides access via RDP to service. This transport can use an domain. If username processed by authenticator contains '@', it will split it and left-@-part will be username, and right password ''' typeName = _('X2GO Transport (direct)') typeType = 'X2GOTransport' typeDescription = _('X2GO Transport for direct connection') iconFile = 'x2go.png' protocol = protocols.NX useEmptyCreds = gui.CheckBoxField(label=_('Empty creds'), order=1, tooltip=_('If checked, the credentials used to connect will be emtpy')) fixedName = gui.TextField(label=_('Username'), order=2, tooltip=_('If not empty, this username will be always used as credential')) fixedPassword = gui.PasswordField(label=_('Password'), order=3, tooltip=_('If not empty, this password will be always used as credential')) listenPort = gui.NumericField(label=_('Listening port'), length=5, order=4, tooltip=_('Listening port of NX (ssh) at client machine'), defvalue='22') connection = gui.ChoiceField(label=_('Connection'), order=6, tooltip=_('Connection speed for this transport (quality)'), values=[ {'id': 'modem', 'text': 'modem'}, {'id': 'isdn', 'text': 'isdn'}, {'id': 'adsl', 'text': 'adsl'}, {'id': 'wan', 'text': 'wan'}, {'id': 'lan', 'text': 'lan'} ]) session = gui.ChoiceField(label=_('Session'), order=7, tooltip=_('Desktop session'), values=[ {'id': 'gnome', 'text': 'gnome'}, {'id': 'kde', 'text': 'kde'}, {'id': 'cde', 'text': 'cde'}, ]) cacheDisk = gui.ChoiceField(label=_('Disk Cache'), order=8, tooltip=_('Cache size en Mb stored at disk'), values=[ {'id': '0', 'text': '0 Mb'}, {'id': '32', 'text': '32 Mb'}, {'id': '64', 'text': '64 Mb'}, {'id': '128', 'text': '128 Mb'}, {'id': '256', 'text': '256 Mb'}, {'id': '512', 'text': '512 Mb'}, ]) cacheMem = gui.ChoiceField(label=_('Memory Cache'), order=9, tooltip=_('Cache size en Mb kept at memory'), values=[ {'id': '4', 'text': '4 Mb'}, {'id': '8', 'text': '8 Mb'}, {'id': '16', 'text': '16 Mb'}, {'id': '32', 'text': '32 Mb'}, {'id': '64', 'text': '64 Mb'}, {'id': '128', 'text': '128 Mb'}, ]) def initialize(self, values): if values is None: return # Just pass over in fact def isAvailableFor(self, ip): ''' Checks if the transport is available for the requested destination ip Override this in yours transports ''' logger.debug('Checking availability for {0}'.format(ip)) ready = self.cache().get(ip) if ready is None: # Check again for readyness if connection.testServer(ip, self.listenPort.value) is True: self.cache().put(ip, 'Y', READY_CACHE_TIMEOUT) return True else: self.cache().put(ip, 'N', READY_CACHE_TIMEOUT) return ready == 'Y' def getUDSTransportScript(self, userService, transport, ip, os, user, password, request): logger.debug('Getting X2Go Transport info') prefs = user.prefs('nx') username = user.getUsernameForAuth() proc = username.split('@') username = proc[0] if self.fixedName.value != '': username = self.fixedName.value if self.fixedPassword.value != '': password = self.fixedPassword.value if self.useEmptyCreds.isTrue(): username, password = '', '' # We have the credentials right now, let os manager width, height = CommonPrefs.getWidthHeight(prefs) # Fix username/password acording to os manager username, password = userService.processUserPassword(username, password) # data data = { 'username': username, 'password': password, 'width': width, 'height': height, 'port': self.listenPort.value, 'connection': self.connection.value, 'session': self.session.value, 'cacheDisk': self.cacheDisk.value, 'cacheMem': self.cacheMem.value } return ''' from PyQt4 import QtCore, QtGui import six from uds import osDetector data = {data} osname = {os} QtGui.QMessageBox.critical(parent, 'Notice ' + osDetector.getOs(), six.text_type(data), QtGui.QMessageBox.Ok) '''.format(data=data, os=os)
class BaseX2GOTransport(Transport): """ Provides access via X2GO to service. This transport can use an domain. If username processed by authenticator contains '@', it will split it and left-@-part will be username, and right password """ iconFile = 'x2go.png' protocol = protocols.X2GO supportedOss = (OsDetector.Linux, OsDetector.Windows) fixedName = gui.TextField( order=2, label=_('Username'), tooltip=_( 'If not empty, this username will be always used as credential'), tab=gui.CREDENTIALS_TAB) fullScreen = gui.CheckBoxField( order=10, label=_('Show fullscreen'), tooltip=_('If checked, viewer will be shown on fullscreen mode-'), tab=gui.PARAMETERS_TAB) desktopType = gui.ChoiceField( label=_('Desktop'), order=11, tooltip=_('Desktop session'), values=[ { 'id': 'XFCE', 'text': 'Xfce' }, { 'id': 'MATE', 'text': 'Mate' }, { 'id': 'LXDE', 'text': 'Lxde' }, { 'id': 'GNOME', 'text': 'Gnome (see docs)' }, { 'id': 'KDE', 'text': 'Kde (see docs)' }, # {'id': 'UNITY', 'text': 'Unity (see docs)'}, { 'id': 'gnome-session-cinnamon', 'text': 'Cinnamon 1.4 (see docs)' }, { 'id': 'gnome-session-cinnamon2d', 'text': 'Cinnamon 2.2 (see docs)' }, { 'id': 'UDSVAPP', 'text': 'UDS vAPP' }, ], tab=gui.PARAMETERS_TAB) customCmd = gui.TextField( order=12, label=_('vAPP'), tooltip= _('If UDS vAPP is selected as "Desktop", the FULL PATH of the app to be executed. If UDS vAPP is not selected, this field will be ignored.' ), tab=gui.PARAMETERS_TAB) sound = gui.CheckBoxField(order=13, label=_('Enable sound'), tooltip=_('If checked, sound will be available'), defvalue=gui.TRUE, tab=gui.PARAMETERS_TAB) exports = gui.CheckBoxField( order=14, label=_('Redirect home folder'), tooltip= _('If checked, user home folder will be redirected. (On linux, also redirects /media)' ), defvalue=gui.FALSE, tab=gui.PARAMETERS_TAB) speed = gui.ChoiceField(label=_('Speed'), order=15, tooltip=_('Connection speed'), defvalue='3', values=[ { 'id': '0', 'text': 'MODEM' }, { 'id': '1', 'text': 'ISDN' }, { 'id': '2', 'text': 'ADSL' }, { 'id': '3', 'text': 'WAN' }, { 'id': '4', 'text': 'LAN' }, ], tab=gui.PARAMETERS_TAB) soundType = gui.ChoiceField(label=_('Sound'), order=30, tooltip=_('Sound server'), defvalue='pulse', values=[ { 'id': 'pulse', 'text': 'Pulse' }, { 'id': 'esd', 'text': 'ESD' }, ], tab=gui.ADVANCED_TAB) keyboardLayout = gui.TextField( label=_('Keyboard'), order=31, tooltip=_( 'Keyboard layout (es, us, fr, ...). Empty value means autodetect.' ), defvalue='', tab=gui.ADVANCED_TAB) # 'nopack', '8', '64', '256', '512', '4k', '32k', '64k', '256k', '2m', '16m' # '256-rdp', '256-rdp-compressed', '32k-rdp', '32k-rdp-compressed', '64k-rdp' # '64k-rdp-compressed', '16m-rdp', '16m-rdp-compressed' # 'rfb-hextile', 'rfb-tight', 'rfb-tight-compressed' # '8-tight', '64-tight', '256-tight', '512-tight', '4k-tight', '32k-tight' # '64k-tight', '256k-tight', '2m-tight', '16m-tight' # '8-jpeg-%', '64-jpeg', '256-jpeg', '512-jpeg', '4k-jpeg', '32k-jpeg' # '64k-jpeg', '256k-jpeg', '2m-jpeg', '16m-jpeg-%' # '8-png-jpeg-%', '64-png-jpeg', '256-png-jpeg', '512-png-jpeg', '4k-png-jpeg' # '32k-png-jpeg', '64k-png-jpeg', '256k-png-jpeg', '2m-png-jpeg', '16m-png-jpeg-%' # '8-png-%', '64-png', '256-png', '512-png', '4k-png' # '32k-png', '64k-png', '256k-png', '2m-png', '16m-png-%' # '16m-rgb-%', '16m-rle-%' pack = gui.TextField(label=_('Pack'), order=32, tooltip=_('Pack format. Change with care!'), defvalue='16m-jpeg', tab=gui.ADVANCED_TAB) quality = gui.NumericField( label=_('Quality'), order=33, tooltip=_('Quality value used on some pack formats.'), length=1, defvalue='6', minValue=1, maxValue=9, required=True, tab=gui.ADVANCED_TAB) def isAvailableFor(self, userService, ip): """ Checks if the transport is available for the requested destination ip Override this in yours transports """ logger.debug('Checking availability for {0}'.format(ip)) ready = self.cache.get(ip) if ready is None: # Check again for ready if connection.testServer(ip, '22') is True: self.cache.put(ip, 'Y', READY_CACHE_TIMEOUT) return True else: self.cache.put(ip, 'N', READY_CACHE_TIMEOUT) return ready == 'Y' def processedUser(self, userService, userName): v = self.processUserPassword(userService, userName, '') return v['username'] def processUserPassword(self, service, user, password): username = user.getUsernameForAuth() if self.fixedName.value != '': username = self.fixedName.value # Fix username/password acording to os manager username, password = service.processUserPassword(username, password) return { 'protocol': self.protocol, 'username': username, 'password': '' } def getConnectionInfo( self, service, user, password ): # Password is ignored in this transport, auth is done using SSH return self.processUserPassword(service, user, password) def genKeyPairForSsh(self): """ Generates a key pair for use with x2go The private part is used by client the public part must be "appended" to authorized_keys if it is not already added. If .ssh folder does not exists, it must be created if authorized_keys does not exists, it must be created On key adition, we can look for every key that has a "UDS@X2GOCLIENT" as comment, so we can remove them before adding new ones Windows (tested): C:\Program Files (x86)\\x2goclient>x2goclient.exe --session-conf=c:/temp/sessions --session=UDS/test-session --close-disconnect --hide --no-menu Linux (tested): HOME=[temporal folder, where we create a .x2goclient folder and a sessions inside] pyhoca-cli -P UDS/test-session """ key = paramiko.RSAKey.generate(SSH_KEY_LENGTH) privFile = six.StringIO() key.write_private_key(privFile) priv = privFile.getvalue() pub = key.get_base64( ) # 'ssh-rsa {} UDS@X2GOCLIENT'.format(key.get_base64()) return priv, pub def getAuthorizeScript(self, user, pubKey): return self.getScript('scripts/authorize.py').replace( '__USER__', user).replace('__KEY__', pubKey) def getAndPushKey(self, user, userService): priv, pub = self.genKeyPairForSsh() authScript = self.getAuthorizeScript(user, pub) userServiceManager().sendScript(userService, authScript) return priv, pub def getScript(self, script): with open(os.path.join(os.path.dirname(__file__), script)) as f: data = f.read() return data
class NXTransport(Transport): ''' Provides access via RDP to service. This transport can use an domain. If username processed by authenticator contains '@', it will split it and left-@-part will be username, and right password ''' typeName = _('NX Transport (direct)') typeType = 'NXTransport' typeDescription = _('NX Transport for direct connection') iconFile = 'nx.png' needsJava = True # If this transport needs java for rendering protocol = protocols.NX useEmptyCreds = gui.CheckBoxField( label=_('Empty creds'), order=1, tooltip=_('If checked, the credentials used to connect will be emtpy')) fixedName = gui.TextField( label=_('Username'), order=2, tooltip=_( 'If not empty, this username will be always used as credential')) fixedPassword = gui.PasswordField( label=_('Password'), order=3, tooltip=_( 'If not empty, this password will be always used as credential')) listenPort = gui.NumericField( label=_('Listening port'), length=5, order=4, tooltip=_('Listening port of NX (ssh) at client machine'), defvalue='22') connection = gui.ChoiceField( label=_('Connection'), order=6, tooltip=_('Connection speed for this transport (quality)'), values=[{ 'id': 'modem', 'text': 'modem' }, { 'id': 'isdn', 'text': 'isdn' }, { 'id': 'adsl', 'text': 'adsl' }, { 'id': 'wan', 'text': 'wan' }, { 'id': 'lan', 'text': 'lan' }]) session = gui.ChoiceField(label=_('Session'), order=7, tooltip=_('Desktop session'), values=[ { 'id': 'gnome', 'text': 'gnome' }, { 'id': 'kde', 'text': 'kde' }, { 'id': 'cde', 'text': 'cde' }, ]) cacheDisk = gui.ChoiceField(label=_('Disk Cache'), order=8, tooltip=_('Cache size en Mb stored at disk'), values=[ { 'id': '0', 'text': '0 Mb' }, { 'id': '32', 'text': '32 Mb' }, { 'id': '64', 'text': '64 Mb' }, { 'id': '128', 'text': '128 Mb' }, { 'id': '256', 'text': '256 Mb' }, { 'id': '512', 'text': '512 Mb' }, ]) cacheMem = gui.ChoiceField(label=_('Memory Cache'), order=9, tooltip=_('Cache size en Mb kept at memory'), values=[ { 'id': '4', 'text': '4 Mb' }, { 'id': '8', 'text': '8 Mb' }, { 'id': '16', 'text': '16 Mb' }, { 'id': '32', 'text': '32 Mb' }, { 'id': '64', 'text': '64 Mb' }, { 'id': '128', 'text': '128 Mb' }, ]) def __init__(self, environment, values=None): super(NXTransport, self).__init__(environment, values) if values is not None: self._useEmptyCreds = gui.strToBool(values['useEmptyCreds']) self._fixedName = values['fixedName'] self._fixedPassword = values['fixedPassword'] self._listenPort = values['listenPort'] self._connection = values['connection'] self._session = values['session'] self._cacheDisk = values['cacheDisk'] self._cacheMem = values['cacheMem'] else: self._useEmptyCreds = '' self._fixedName = '' self._fixedPassword = '' self._listenPort = '' self._connection = '' self._session = '' self._cacheDisk = '' self._cacheMem = '' def marshal(self): ''' Serializes the transport data so we can store it in database ''' return str.join('\t', [ 'v1', gui.boolToStr(self._useEmptyCreds), self._fixedName, self._fixedPassword, self._listenPort, self._connection, self._session, self._cacheDisk, self._cacheMem ]) def unmarshal(self, string): data = string.split('\t') if data[0] == 'v1': self._useEmptyCreds = gui.strToBool(data[1]) self._fixedName, self._fixedPassword, self._listenPort, self._connection, self._session, self._cacheDisk, self._cacheMem = data[ 2:] def valuesDict(self): return { 'useEmptyCreds': gui.boolToStr(self._useEmptyCreds), 'fixedName': self._fixedName, 'fixedPassword': self._fixedPassword, 'listenPort': self._listenPort, 'connection': self._connection, 'session': self._session, 'cacheDisk': self._cacheDisk, 'cacheMem': self._cacheMem } def isAvailableFor(self, ip): ''' Checks if the transport is available for the requested destination ip Override this in yours transports ''' logger.debug('Checking availability for {0}'.format(ip)) ready = self.cache().get(ip) if ready is None: # Check again for readyness if connection.testServer(ip, self._listenPort) is True: self.cache().put(ip, 'Y', READY_CACHE_TIMEOUT) return True else: self.cache().put(ip, 'N', READY_CACHE_TIMEOUT) return ready == 'Y' def renderForHtml(self, userService, transport, ip, os, user, password): prefs = user.prefs('nx') username = user.getUsernameForAuth() proc = username.split('@') username = proc[0] if self._fixedName is not '': username = self._fixedName if self._fixedPassword is not '': password = self._fixedPassword if self._useEmptyCreds is True: username, password = '', '' # We have the credentials right now, let os manager width, height = CommonPrefs.getWidthHeight(prefs) # Extra data extra = { 'width': width, 'height': height, 'port': self._listenPort, 'connection': self._connection, 'session': self._session, 'cacheDisk': self._cacheDisk, 'cacheMem': self._cacheMem } # Fix username/password acording to os manager username, password = userService.processUserPassword( username, password) return generateHtmlForNX(self, userService.uuid, transport.uuid, ip, os, username, password, extra) def getHtmlComponent(self, theId, os, componentId): # We use helper to keep this clean return getHtmlComponent(self.__module__, componentId)