1
0
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:
Adolfo Gómez 2012-11-26 13:39:22 +00:00
parent b298b5e3ad
commit 710b56d4e1
17 changed files with 224 additions and 26 deletions

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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):
'''

View File

@ -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)

View File

@ -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)

View File

@ -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

View File

@ -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)

View File

@ -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>'),

View File

@ -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)

View File

@ -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):

View File

@ -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)

View File

@ -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)

View File

@ -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):

View File

@ -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):

View File

@ -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)

View File

@ -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))