mirror of
https://github.com/dkmstr/openuds.git
synced 2024-12-22 13:34:04 +03:00
* Added support for OS Managers to change services passwords.
* oVirt should be usable right now, testing and fixing minor bugs * Added support for Windows Support with password changing of user to new one * Minor improvements (to code)
This commit is contained in:
parent
b298b5e3ad
commit
710b56d4e1
@ -105,6 +105,7 @@ encoding//src/uds/models.py=utf-8
|
||||
encoding//src/uds/osmanagers/LinuxOsManager/LinuxOsManager.py=utf-8
|
||||
encoding//src/uds/osmanagers/LinuxOsManager/__init__.py=utf-8
|
||||
encoding//src/uds/osmanagers/WindowsOsManager/WinDomainOsManager.py=utf-8
|
||||
encoding//src/uds/osmanagers/WindowsOsManager/WinRandomPassOsManager.py=utf-8
|
||||
encoding//src/uds/osmanagers/WindowsOsManager/WindowsOsManager.py=utf-8
|
||||
encoding//src/uds/osmanagers/WindowsOsManager/__init__.py=utf-8
|
||||
encoding//src/uds/osmanagers/__init__.py=utf-8
|
||||
|
@ -116,6 +116,23 @@ class OSManager(Module):
|
||||
'''
|
||||
pass
|
||||
|
||||
def processUserPassword(self, service, username, password):
|
||||
'''
|
||||
This will be invoked prior to passsing username/password to Transport.
|
||||
|
||||
This method allows us to "change" username and/or password "on the fly".
|
||||
One example of use of this is an OS Manager that creates a random password for an user.
|
||||
In that case, this method, if the username passed in is the same as the os manager changes the password for, return the changed password.
|
||||
|
||||
MUST Return:
|
||||
An array with 2 elements, [newUserName, newPassword].
|
||||
Default method simplt does nothing with in parameters, just returns it. (So, if your os manager does not need this,
|
||||
simply do not implement it)
|
||||
|
||||
Note: This method is, right now, invoked by Transports directly. So if you implement a Transport, remember to invoke this
|
||||
'''
|
||||
return [username, password]
|
||||
|
||||
def destroy(self):
|
||||
'''
|
||||
Invoked when OS Manager is deleted
|
||||
|
@ -101,9 +101,10 @@ class Transport(Module):
|
||||
'''
|
||||
return cls.supportedOss.count(osName) > 0
|
||||
|
||||
def renderForHtml(self, id, ip, os, user, password):
|
||||
def renderForHtml(self, userService, id, ip, os, user, password):
|
||||
'''
|
||||
Requests the html rendering of connector for the destination ip, (dbUser) and password
|
||||
@param: userService: DeployedUserService for witch we are rendering the connection (db model)
|
||||
@param id: id of the transport
|
||||
@param ip: ip of the destination
|
||||
@param user: user (dbUser) logged in
|
||||
|
@ -1073,7 +1073,7 @@ class DeployedServicePublication(models.Model):
|
||||
if self.data != '' and self.data is not None:
|
||||
dpl.unserialize(self.data)
|
||||
return dpl
|
||||
|
||||
|
||||
def updateData(self, dsp):
|
||||
'''
|
||||
Updates the data field with the serialized uds.core.services.Publication
|
||||
@ -1236,6 +1236,57 @@ class UserService(models.Model):
|
||||
:note: This method do not saves the updated record, just updates the field
|
||||
'''
|
||||
self.data = us.serialize()
|
||||
|
||||
def getName(self):
|
||||
'''
|
||||
Returns the name of the user deployed service
|
||||
'''
|
||||
if self.friendly_name == '':
|
||||
si = self.getInstance()
|
||||
self.friendly_name = si.getName()
|
||||
self.updateData(si)
|
||||
|
||||
return self.friendly_name
|
||||
|
||||
def getUniqueId(self):
|
||||
'''
|
||||
Returns the unique id of the user deployed service
|
||||
'''
|
||||
if self.unique_id == '':
|
||||
si = self.getInstance()
|
||||
self.unique_id = si.getUniqueId()
|
||||
self.updateData(si)
|
||||
return self.unique_id
|
||||
|
||||
def storeValue(self, name, value):
|
||||
'''
|
||||
Stores a value inside custom storage
|
||||
|
||||
Args:
|
||||
name: Name of the value to store
|
||||
value: Value of the value to store
|
||||
'''
|
||||
self.getEnvironment().storage().put(name, value)
|
||||
|
||||
def recoverValue(self, name):
|
||||
'''
|
||||
Recovers a value from custom storage
|
||||
|
||||
Args:
|
||||
name: Name of values to recover
|
||||
|
||||
Returns:
|
||||
Stored value, None if no value was stored
|
||||
'''
|
||||
return self.getEnvironment().storage().get(name)
|
||||
|
||||
def processUserPassword(self, username, password):
|
||||
ds = self.deployed_service
|
||||
serviceInstance = ds.service.getInstance()
|
||||
if serviceInstance.needsManager is False:
|
||||
return [username, password]
|
||||
|
||||
return ds.osmanager.getInstance().processUserPassword(self, username, password)
|
||||
|
||||
def setState(self, state):
|
||||
'''
|
||||
|
@ -67,13 +67,13 @@ class LinuxOsManager(osmanagers.OSManager):
|
||||
'''
|
||||
gets name from deployed
|
||||
'''
|
||||
si = service.getInstance()
|
||||
name = si.getName()
|
||||
service.updateData(si)
|
||||
return name
|
||||
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, si, data):
|
||||
# Notifies IP to deployed
|
||||
@ -87,7 +87,8 @@ class LinuxOsManager(osmanagers.OSManager):
|
||||
def process(self,service,msg, data):
|
||||
'''
|
||||
We understand this messages:
|
||||
* msg = info, data = None. Get information about name of machine (or domain, in derived WinDomainOsManager class)
|
||||
* 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
|
||||
@ -99,9 +100,14 @@ class LinuxOsManager(osmanagers.OSManager):
|
||||
notifyReady = False
|
||||
doRemove = False
|
||||
state = service.os_state
|
||||
|
||||
# Old "info" state, will be removed in a near future
|
||||
if msg == "info":
|
||||
ret = self.infoVal(service)
|
||||
state = State.PREPARING
|
||||
elif msg == "information":
|
||||
ret = self.infoValue(service)
|
||||
state = State.PREPARING
|
||||
elif msg == "login":
|
||||
si = service.getInstance()
|
||||
si.userLoggedIn(data)
|
||||
|
@ -56,6 +56,9 @@ class WinDomainOsManager(WindowsOsManager):
|
||||
super(WinDomainOsManager,self).release(service)
|
||||
# TODO: remove machine from active directory os, under ou or default location if not specified
|
||||
|
||||
def infoVal(self, service):
|
||||
return 'domain:{0}\t{1}\t{2}\t{3}\t{4}'.format( self.getName(service), self._domain, self._ou, self._account, self._password)
|
||||
|
||||
def infoVal(self, service):
|
||||
return 'domain:{0}\t{1}\t{2}\t{3}\t{4}'.format( self.getName(service), self._domain, self._ou, self._account, self._password)
|
||||
|
||||
|
@ -0,0 +1,90 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
#
|
||||
# Copyright (c) 2012 Virtual Cable S.L.
|
||||
# All rights reserved.
|
||||
#
|
||||
|
||||
'''
|
||||
@author: Adolfo Gómez, dkmaster at dkmon dot com
|
||||
'''
|
||||
|
||||
from django.utils.translation import ugettext_noop as _
|
||||
from uds.core.ui.UserInterface import gui
|
||||
from uds.core.managers.CryptoManager import CryptoManager
|
||||
from uds.core import osmanagers
|
||||
from WindowsOsManager import WindowsOsManager, scrambleMsg
|
||||
|
||||
import logging
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
class WinRandomPassManager(WindowsOsManager):
|
||||
typeName = _('Windows Random Password OS Manager')
|
||||
typeType = 'WinRandomPasswordManager'
|
||||
typeDescription = _('Os Manager to control windows machines, with user password set randomly.')
|
||||
iconFile = 'wosmanager.png'
|
||||
|
||||
# Apart form data from windows os manager, we need also domain and credentials
|
||||
userAccount = gui.TextField(length=64, label = _('Account'), order = 2, tooltip = _('User account to change password'), required = True)
|
||||
password = gui.PasswordField(length=64, label = _('Password'), order = 3, tooltip = _('Current (template) password of the user account'), required = True)
|
||||
|
||||
# Inherits base "onLogout"
|
||||
onLogout = WindowsOsManager.onLogout
|
||||
|
||||
def __init__(self,environment, values):
|
||||
super(WinRandomPassManager, self).__init__(environment, values)
|
||||
if values != None:
|
||||
if values['userAccount'] == '':
|
||||
raise osmanagers.OSManager.ValidationException(_('Must provide an user account!!!'))
|
||||
if values['password'] == '':
|
||||
raise osmanagers.OSManager.ValidationException(_('Must provide a password for the account!!!'))
|
||||
self._userAccount = values['userAccount']
|
||||
self._password = values['password']
|
||||
else:
|
||||
self._userAccount = ''
|
||||
self._password = ""
|
||||
|
||||
def release(self, service):
|
||||
super(WinRandomPassManager,self).release(service)
|
||||
|
||||
def processUserPassword(self, service, username, password):
|
||||
if username == self._userAccount:
|
||||
return [username, service.recoverValue('winOsRandomPass')]
|
||||
return [username, password]
|
||||
|
||||
def genPassword(self, service):
|
||||
import random
|
||||
import string
|
||||
randomPass = service.recoverValue('winOsRandomPass')
|
||||
if randomPass is None:
|
||||
randomPass = ''.join(random.choice(string.ascii_letters + string.digits) for _ in range(16))
|
||||
service.storeValue('winOsRandomPass', randomPass)
|
||||
return randomPass
|
||||
|
||||
def infoVal(self, service):
|
||||
return 'rename:{0}\t{1}\t{2}\t{3}'.format( self.getName(service), self._userAccount, self._password, self.genPassword(service))
|
||||
|
||||
def infoValue(self, service):
|
||||
return 'rename\r{0}\t{1}\t{2}\t{3}'.format( self.getName(service), self._userAccount, self._password, self.genPassword(service))
|
||||
|
||||
def marshal(self):
|
||||
base = super(WinRandomPassManager,self).marshal()
|
||||
'''
|
||||
Serializes the os manager data so we can store it in database
|
||||
'''
|
||||
return str.join( '\t', [ 'v1', self._userAccount, CryptoManager.manager().encrypt(self._password), base.encode('hex') ] )
|
||||
|
||||
def unmarshal(self, s):
|
||||
data = s.split('\t')
|
||||
if data[0] == 'v1':
|
||||
self._userAccount = data[1]
|
||||
self._password = CryptoManager.manager().decrypt(data[2])
|
||||
super(WinRandomPassManager, self).unmarshal(data[3].decode('hex'))
|
||||
|
||||
def valuesDict(self):
|
||||
dic = super(WinRandomPassManager,self).valuesDict()
|
||||
dic['userAccount'] = self._userAccount
|
||||
dic['password'] = self._password
|
||||
return dic
|
||||
|
@ -68,13 +68,13 @@ class WindowsOsManager(osmanagers.OSManager):
|
||||
'''
|
||||
gets name from deployed
|
||||
'''
|
||||
si = service.getInstance()
|
||||
name = si.getName()
|
||||
service.updateData(si)
|
||||
return name
|
||||
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, si, data):
|
||||
# Notifies IP to deployed
|
||||
@ -88,7 +88,8 @@ class WindowsOsManager(osmanagers.OSManager):
|
||||
def process(self,service,msg, data):
|
||||
'''
|
||||
We understand this messages:
|
||||
* msg = info, data = None. Get information about name of machine (or domain, in derived WinDomainOsManager class)
|
||||
* 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
|
||||
@ -103,6 +104,9 @@ class WindowsOsManager(osmanagers.OSManager):
|
||||
if msg == "info":
|
||||
ret = self.infoVal(service)
|
||||
state = State.PREPARING
|
||||
elif msg == "information":
|
||||
ret = self.infoValue(service)
|
||||
state = State.PREPARING
|
||||
elif msg == "logon":
|
||||
si = service.getInstance()
|
||||
si.userLoggedIn(data)
|
||||
|
@ -12,12 +12,14 @@
|
||||
from django.utils.translation import ugettext_noop as _
|
||||
from uds.core.osmanagers.OSManagersFactory import OSManagersFactory
|
||||
from uds.core.managers.DownloadsManager import DownloadsManager
|
||||
from uds.osmanagers.WindowsOsManager.WindowsOsManager import WindowsOsManager
|
||||
from uds.osmanagers.WindowsOsManager.WinDomainOsManager import WinDomainOsManager
|
||||
from WindowsOsManager import WindowsOsManager
|
||||
from WinDomainOsManager import WinDomainOsManager
|
||||
from WinRandomPassOsManager import WinRandomPassManager
|
||||
import os.path, sys
|
||||
|
||||
OSManagersFactory.factory().insert(WindowsOsManager)
|
||||
OSManagersFactory.factory().insert(WinDomainOsManager)
|
||||
OSManagersFactory.factory().insert(WinRandomPassManager)
|
||||
|
||||
DownloadsManager.manager().registerDownloadable('UDSActorSetup.exe',
|
||||
_('UDS Actor for windows machines <b>(Important!! Requires .net framework 3.5 sp1)</b>'),
|
||||
|
@ -215,10 +215,17 @@ class OVirtLinkedDeployment(UserDeployment):
|
||||
if state == 'unknown' and chkState != 'unknown':
|
||||
return self.__error('Machine not found')
|
||||
|
||||
if state != chkState:
|
||||
return State.RUNNING
|
||||
ret = State.RUNNING
|
||||
if type(chkState) is list:
|
||||
for cks in chkState:
|
||||
if state == cks:
|
||||
ret = State.FINISHED
|
||||
break
|
||||
else:
|
||||
if state == chkState:
|
||||
ret = State.FINISHED
|
||||
|
||||
return State.FINISHED
|
||||
return ret
|
||||
|
||||
def __getCurrentOp(self):
|
||||
if len(self._queue) == 0:
|
||||
@ -306,8 +313,8 @@ class OVirtLinkedDeployment(UserDeployment):
|
||||
Deploys a machine from template for user/cache
|
||||
'''
|
||||
templateId = self.publication().getTemplateId()
|
||||
name = self.service().sanitizeVmName('UDS service ' + self.getName())
|
||||
comments = 'UDS Linked clone for'
|
||||
name = self.service().sanitizeVmName(self.getName()) # oVirt don't let us to create machines with more than 15 chars!!!
|
||||
comments = 'UDS Linked clone'
|
||||
|
||||
self._vmid = self.service().deployFromTemplate(name, comments, templateId)
|
||||
if self._vmid is None:
|
||||
@ -322,8 +329,9 @@ class OVirtLinkedDeployment(UserDeployment):
|
||||
if state == 'unknown':
|
||||
raise Exception('Machine not found')
|
||||
|
||||
if state != 'down' and state != 'suspended':
|
||||
if state != 'down':
|
||||
self.__pushFrontOp(opStop)
|
||||
self.__executeQueue()
|
||||
else:
|
||||
self.service().removeMachine(self._vmid)
|
||||
|
||||
@ -356,7 +364,7 @@ class OVirtLinkedDeployment(UserDeployment):
|
||||
if state == 'down': # Already stoped, return
|
||||
return
|
||||
|
||||
if state != 'up':
|
||||
if state != 'up' and state != 'suspended':
|
||||
self.__pushBackOp(opRetry) # Will call "check Retry", that will finish inmediatly and again call this one
|
||||
else:
|
||||
self.service().stopMachine(self._vmid)
|
||||
|
@ -204,6 +204,7 @@ class OVirtLinkedService(Service):
|
||||
Returns:
|
||||
Id of the machine being created form template
|
||||
'''
|
||||
logger.debug('Deploying from template {0} machine {1}'.format(templateId, name))
|
||||
return self.parent().deployFromTemplate(name, comments, templateId, self.cluster.value, self.display.value)
|
||||
|
||||
def removeTemplate(self, templateId):
|
||||
|
@ -421,6 +421,8 @@ class Client(object):
|
||||
|
||||
api = self.__getApi()
|
||||
|
||||
logger.debug('Deploying machine {0}'.format(name))
|
||||
|
||||
cluster = params.Cluster(id=clusterId)
|
||||
template = params.Template(id=templateId)
|
||||
display = params.Display(type_=displayType)
|
||||
|
@ -148,7 +148,7 @@ class NXTransport(Transport):
|
||||
self.cache().put(ip, 'N', READY_CACHE_TIMEOUT)
|
||||
return ready == 'Y'
|
||||
|
||||
def renderForHtml(self, theId, ip, os, user, password):
|
||||
def renderForHtml(self, userService, theId, ip, os, user, password):
|
||||
|
||||
prefs = user.prefs('nx')
|
||||
|
||||
@ -162,6 +162,8 @@ class NXTransport(Transport):
|
||||
if self._useEmptyCreds is True:
|
||||
username, password = '',''
|
||||
|
||||
# We have the credentials right now, let os manager
|
||||
|
||||
width, height = CommonPrefs.getWidthHeight(prefs)
|
||||
|
||||
# Extra data
|
||||
@ -170,6 +172,8 @@ class NXTransport(Transport):
|
||||
'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, theId, ip, username, password, extra)
|
||||
|
||||
|
@ -105,7 +105,7 @@ class RDPTransport(Transport):
|
||||
self.cache().put(ip, 'N', READY_CACHE_TIMEOUT)
|
||||
return ready == 'Y'
|
||||
|
||||
def renderForHtml(self, id, ip, os, user, password):
|
||||
def renderForHtml(self, userService, id, ip, os, user, password):
|
||||
# We use helper to keep this clean
|
||||
username = user.getUsernameForAuth()
|
||||
prefs = user.prefs('rdp')
|
||||
@ -133,6 +133,9 @@ class RDPTransport(Transport):
|
||||
'printers' : self._allowPrinters, 'smartcards' : self._allowSmartcards,
|
||||
'drives' : self._allowDrives, 'serials' : self._allowSerials, 'compression':True }
|
||||
|
||||
# Fix username/password acording to os manager
|
||||
username, password = userService.processUserPassword(username, password)
|
||||
|
||||
return generateHtmlForRdp(self, id, os, ip, '3389', username, password, domain, extra)
|
||||
|
||||
def getHtmlComponent(self, id, os, componentId):
|
||||
|
@ -116,7 +116,7 @@ class TSRDPTransport(Transport):
|
||||
self.cache().put(ip, 'N', READY_CACHE_TIMEOUT)
|
||||
return ready == 'Y'
|
||||
|
||||
def renderForHtml(self, id, ip, os, user, password):
|
||||
def renderForHtml(self, userService, id, ip, os, user, password):
|
||||
# We use helper to keep this clean
|
||||
username = user.getUsernameForAuth()
|
||||
prefs = user.prefs('rdp')
|
||||
@ -156,6 +156,9 @@ class TSRDPTransport(Transport):
|
||||
'drives' : self._allowDrives, 'serials' : self._allowSerials,
|
||||
'tun': tun, 'compression':True }
|
||||
|
||||
# Fix username/password acording to os manager
|
||||
username, password = userService.processUserPassword(username, password)
|
||||
|
||||
return generateHtmlForRdp(self, id, os, ip, '-1', username, password, domain, extra)
|
||||
|
||||
def getHtmlComponent(self, id, os, componentId):
|
||||
|
@ -158,7 +158,7 @@ class TSNXTransport(Transport):
|
||||
self.cache().put(ip, 'N', READY_CACHE_TIMEOUT)
|
||||
return ready == 'Y'
|
||||
|
||||
def renderForHtml(self, theId, ip, os, user, password):
|
||||
def renderForHtml(self, userService, theId, ip, os, user, password):
|
||||
|
||||
prefs = user.prefs('nx')
|
||||
|
||||
@ -191,6 +191,8 @@ class TSNXTransport(Transport):
|
||||
'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, theId, username, password, extra)
|
||||
|
||||
|
@ -222,7 +222,7 @@ def service(request, idService, idTransport):
|
||||
if ip is not None:
|
||||
itrans = trans.getInstance()
|
||||
if itrans.isAvailableFor(ip):
|
||||
transport = itrans.renderForHtml(scrambleId(request, trans.id), ip, request.session['OS'], request.user, webPassword(request))
|
||||
transport = itrans.renderForHtml(ads, scrambleId(request, trans.id), ip, request.session['OS'], request.user, webPassword(request))
|
||||
return render_to_response('uds/show_transport.html', {'transport' : transport, 'nolang' : True }, context_instance=RequestContext(request))
|
||||
else:
|
||||
logger.debug('Transport is not ready for user service {0}'.format(ads))
|
||||
|
Loading…
Reference in New Issue
Block a user