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:
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'):
v = self.validateRequestKey()
if v is not None:
@ -142,7 +142,10 @@ class Actor(Handler):
if service.deployed_service.osmanager is not None:
maxIdle = service.deployed_service.osmanager.getInstance().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')
# Must be invoked as '/rest/actor/UUID/[message], with message data in post body
@ -170,7 +173,7 @@ class Actor(Handler):
username = ''
if message == 'notifyComms':
service.setProperty('comms_url', data)
service.setCommsUrl(data)
return Actor.result('ok')
# Preprocess some messages, common to all clients, such as "log"
@ -181,7 +184,7 @@ class Actor(Handler):
username = data
try:
res = service.getInstance().osmanager().process(service, message, data)
res = service.getInstance().osmanager().process(service, message, data, options={'scramble': False})
except Exception as e:
return Actor.result(six.text_type(e), ERR_OSMANAGER_ERROR)

View File

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

View File

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

View File

@ -45,6 +45,8 @@ from uds.core.services.Exceptions import MaxServicesReachedException
from uds.models import UserService, getSqlDatetime
from uds.core import services
from uds.core.services import Service
import requests
import json
import logging
logger = logging.getLogger(__name__)
@ -444,6 +446,46 @@ class UserServiceManager(object):
UserServiceOpChecker.makeUnique(uService, ui, state)
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):
'''
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 import Module
__updated__ = '2014-12-01'
__updated__ = '2014-12-04'
STORAGE_KEY = 'osmk'
@ -89,7 +89,7 @@ class OSManager(Module):
pass
# 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.
@param service: Service that sends the request (virtual machine or whatever)
@ -126,6 +126,14 @@ class OSManager(Module):
'''
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
def transformsUserOrPasswordForService(cls):
'''

View File

@ -35,7 +35,7 @@
from __future__ import unicode_literals
__updated__ = '2014-12-02'
__updated__ = '2014-12-04'
from django.db import models
from django.db.models import signals
@ -246,11 +246,14 @@ class UserService(UUIDModel):
'''
return [self.src_ip, self.src_hostname]
def getOsManager(self):
return self.deployed_service.osmanager
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)
'''
return self.deployed_service.osmanager is not None
return self.getOsManager() is not None
def transformsUserOrPasswordForService(self):
'''
@ -419,9 +422,15 @@ class UserService(UUIDModel):
def setProperty(self, propName, propValue):
prop, _ = self.properties.get_or_create(name=propName)
prop.value = propValue
prop.value = propValue if propValue is None else ''
prop.save()
def setCommsUrl(self, commsUrl=None):
self.setProperty('comms_url', commsUrl)
def getCommsUrl(self):
return self.getProperty('comms_url', None)
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,
State.toString(self.state), State.toString(self.os_state))

View File

@ -115,7 +115,7 @@ class WindowsOsManager(osmanagers.OSManager):
except Exception:
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:
* 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:
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):

View File

@ -276,6 +276,7 @@ def service(request, idService, idTransport):
if ip is not None:
itrans = trans.getInstance()
if itrans.isAvailableFor(ip):
UserServiceManager.manager().manageOsManagerPreConnection(ads, request.user)
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))
return render_to_response(theme.template('show_transport.html'), {'transport': transport, 'nolang': True}, context_instance=RequestContext(request))