Adding support for pre-access scripts so UDS can support certain

operations (i.e. add an user to an specific group, or allowing user to
access using specific protocol, thanks to José Luis Sepúlveda from upv
for the feedback ;-)
This commit is contained in:
Adolfo Gómez García 2014-12-04 13:03:58 +01:00
parent 2159e0f29d
commit 9a86682c9d
8 changed files with 77 additions and 11 deletions

View File

@ -122,7 +122,7 @@ class Actor(Handler):
if len(self._args) < 1: if len(self._args) < 1:
raise RequestError('Invalid request') raise RequestError('Invalid request')
# if path is .../test (/rest/actor/[test|init]?key=.....&version=....&id=....) # if path is .../test (/rest/actor/[test|init]?key=.....&version=....&id=....) version & ids are only used on init
if self._args[0] in ('test', 'init'): if self._args[0] in ('test', 'init'):
v = self.validateRequestKey() v = self.validateRequestKey()
if v is not None: if v is not None:
@ -142,7 +142,10 @@ class Actor(Handler):
if service.deployed_service.osmanager is not None: if service.deployed_service.osmanager is not None:
maxIdle = service.deployed_service.osmanager.getInstance().maxIdle() maxIdle = service.deployed_service.osmanager.getInstance().maxIdle()
logger.debug('Max idle: {}'.format(maxIdle)) logger.debug('Max idle: {}'.format(maxIdle))
return Actor.result((service.uuid, service.unique_id, 0 if maxIdle is None else maxIdle)) return Actor.result((service.uuid,
service.unique_id,
0 if maxIdle is None else maxIdle)
)
raise RequestError('Invalid request') raise RequestError('Invalid request')
# Must be invoked as '/rest/actor/UUID/[message], with message data in post body # Must be invoked as '/rest/actor/UUID/[message], with message data in post body
@ -170,7 +173,7 @@ class Actor(Handler):
username = '' username = ''
if message == 'notifyComms': if message == 'notifyComms':
service.setProperty('comms_url', data) service.setCommsUrl(data)
return Actor.result('ok') return Actor.result('ok')
# Preprocess some messages, common to all clients, such as "log" # Preprocess some messages, common to all clients, such as "log"
@ -181,7 +184,7 @@ class Actor(Handler):
username = data username = data
try: try:
res = service.getInstance().osmanager().process(service, message, data) res = service.getInstance().osmanager().process(service, message, data, options={'scramble': False})
except Exception as e: except Exception as e:
return Actor.result(six.text_type(e), ERR_OSMANAGER_ERROR) return Actor.result(six.text_type(e), ERR_OSMANAGER_ERROR)

View File

@ -155,6 +155,7 @@ class CachedService(AssignedService):
{'friendly_name': {'title': _('Friendly name')}}, {'friendly_name': {'title': _('Friendly name')}},
{'state': {'title': _('State'), 'type': 'dict', 'dict': State.dictionary()}}, {'state': {'title': _('State'), 'type': 'dict', 'dict': State.dictionary()}},
{'cache_level': {'title': _('Cache level')}}, {'cache_level': {'title': _('Cache level')}},
{'actor_version': {'title': _('Actor version')}}
] ]
def getLogs(self, parent, item): def getLogs(self, parent, item):

View File

@ -47,7 +47,7 @@ import logging
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
__updated__ = '2014-11-12' __updated__ = '2014-12-04'
# a few constants # a few constants

View File

@ -45,6 +45,8 @@ from uds.core.services.Exceptions import MaxServicesReachedException
from uds.models import UserService, getSqlDatetime from uds.models import UserService, getSqlDatetime
from uds.core import services from uds.core import services
from uds.core.services import Service from uds.core.services import Service
import requests
import json
import logging import logging
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
@ -444,6 +446,46 @@ class UserServiceManager(object):
UserServiceOpChecker.makeUnique(uService, ui, state) UserServiceOpChecker.makeUnique(uService, ui, state)
return False return False
def manageOsManagerPreConnection(self, uService, user):
'''
Sends, if the user service has os manager and the os manager "wants" to send an pre-script to actor
the script to the Service
If fails, it will silently ignore it, but probably connection will not success
This is so right now to keep compatibility with previos xmlrpc actor..
@return: Nothing
'''
logger.debug('Managing specific OS Manager data before connection')
if uService.needsOsManager() is False:
logger.debug('No os manager for service, finishing')
return
osm = uService.getOsManager()
instanceOsManager = osm.getInstance()
script = instanceOsManager.preAccessScript(uService, user)
if script is None:
logger.debug('OS Manager does not provides a pre access script')
logger.debug('Pre access script: {}'.format(script))
return self.sendScript(uService, script)
def sendScript(self, uService, script):
'''
If allowed, send script to user service
'''
url = uService.getCommsUrl()
if url is None:
logger.error('Can\'t connect with actor (no actor or legacy actor)')
return
try:
r = requests.post(url, data={'script': script}, headers={'content-type': 'application/json'}, verify=False, timeout=5)
r = json.loads(r.content)
# In fact we ignore result right now
except Exception as e:
logger.error('Exception caught sending script: {}. Check connection on destination machine: {}'.format(e, url))
# All done
def checkForRemoval(self, uService): def checkForRemoval(self, uService):
''' '''
This method is used by UserService when a request for setInUse(False) is made This method is used by UserService when a request for setInUse(False) is made

View File

@ -36,7 +36,7 @@ from django.utils.translation import ugettext_noop as _
from uds.core.util.State import State from uds.core.util.State import State
from uds.core import Module from uds.core import Module
__updated__ = '2014-12-01' __updated__ = '2014-12-04'
STORAGE_KEY = 'osmk' STORAGE_KEY = 'osmk'
@ -89,7 +89,7 @@ class OSManager(Module):
pass pass
# These methods must be overriden # These methods must be overriden
def process(self, service, message, data): def process(self, service, message, data, options=None):
''' '''
This method must be overriden so your so manager can manage requests and responses from agent. This method must be overriden so your so manager can manage requests and responses from agent.
@param service: Service that sends the request (virtual machine or whatever) @param service: Service that sends the request (virtual machine or whatever)
@ -126,6 +126,14 @@ class OSManager(Module):
''' '''
return None return None
def preAccessScript(self, userService, user):
'''
This gives us the chance to include "customized" initialization for any os manager for an specifyc user & service on assignation to an user
such as "include" in allowed user list, etc...
Both values are db objects
'''
return None
@classmethod @classmethod
def transformsUserOrPasswordForService(cls): def transformsUserOrPasswordForService(cls):
''' '''

View File

@ -35,7 +35,7 @@
from __future__ import unicode_literals from __future__ import unicode_literals
__updated__ = '2014-12-02' __updated__ = '2014-12-04'
from django.db import models from django.db import models
from django.db.models import signals from django.db.models import signals
@ -246,11 +246,14 @@ class UserService(UUIDModel):
''' '''
return [self.src_ip, self.src_hostname] return [self.src_ip, self.src_hostname]
def getOsManager(self):
return self.deployed_service.osmanager
def needsOsManager(self): def needsOsManager(self):
''' '''
Returns True if this User Service needs an os manager (i.e. parent services pools is marked to use an os manager) Returns True if this User Service needs an os manager (i.e. parent services pools is marked to use an os manager)
''' '''
return self.deployed_service.osmanager is not None return self.getOsManager() is not None
def transformsUserOrPasswordForService(self): def transformsUserOrPasswordForService(self):
''' '''
@ -419,9 +422,15 @@ class UserService(UUIDModel):
def setProperty(self, propName, propValue): def setProperty(self, propName, propValue):
prop, _ = self.properties.get_or_create(name=propName) prop, _ = self.properties.get_or_create(name=propName)
prop.value = propValue prop.value = propValue if propValue is None else ''
prop.save() prop.save()
def setCommsUrl(self, commsUrl=None):
self.setProperty('comms_url', commsUrl)
def getCommsUrl(self):
return self.getProperty('comms_url', None)
def __str__(self): def __str__(self):
return "User service {0}, cache_level {1}, user {2}, name {3}, state {4}:{5}".format(self.id, self.cache_level, self.user, self.friendly_name, return "User service {0}, cache_level {1}, user {2}, name {3}, state {4}:{5}".format(self.id, self.cache_level, self.user, self.friendly_name,
State.toString(self.state), State.toString(self.os_state)) State.toString(self.state), State.toString(self.os_state))

View File

@ -115,7 +115,7 @@ class WindowsOsManager(osmanagers.OSManager):
except Exception: except Exception:
log.doLog(service, log.ERROR, "do not understand {0}".format(data), origin) log.doLog(service, log.ERROR, "do not understand {0}".format(data), origin)
def process(self, service, msg, data): def process(self, service, msg, data, options):
''' '''
We understand this messages: We understand this messages:
* msg = info, data = None. Get information about name of machine (or domain, in derived WinDomainOsManager class) (old method) * msg = info, data = None. Get information about name of machine (or domain, in derived WinDomainOsManager class) (old method)
@ -180,6 +180,8 @@ class WindowsOsManager(osmanagers.OSManager):
else: else:
UserServiceManager.manager().notifyReadyFromOsManager(service, '') UserServiceManager.manager().notifyReadyFromOsManager(service, '')
logger.debug('Returning {} to {} message'.format(ret, msg)) 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) return scrambleMsg(ret)
def processUnused(self, userService): def processUnused(self, userService):

View File

@ -276,6 +276,7 @@ def service(request, idService, idTransport):
if ip is not None: if ip is not None:
itrans = trans.getInstance() itrans = trans.getInstance()
if itrans.isAvailableFor(ip): if itrans.isAvailableFor(ip):
UserServiceManager.manager().manageOsManagerPreConnection(ads, request.user)
log.doLog(ads, log.INFO, "User service ready, rendering transport", log.WEB) log.doLog(ads, log.INFO, "User service ready, rendering transport", log.WEB)
transport = itrans.renderForHtml(ads, ads.uuid, trans.uuid, ip, request.session['OS'], request.user, webPassword(request)) transport = itrans.renderForHtml(ads, ads.uuid, trans.uuid, ip, request.session['OS'], request.user, webPassword(request))
return render_to_response(theme.template('show_transport.html'), {'transport': transport, 'nolang': True}, context_instance=RequestContext(request)) return render_to_response(theme.template('show_transport.html'), {'transport': transport, 'nolang': True}, context_instance=RequestContext(request))