def growL1Cache(self, servicePool: ServicePool, cacheL1: int, cacheL2: int, assigned: int) -> None: """ This method tries to enlarge L1 cache. If for some reason the number of deployed services (Counting all, ACTIVE and PREPARING, assigned, L1 and L2) is over max allowed service deployments, this method will not grow the L1 cache """ logger.debug('Growing L1 cache creating a new service for %s', servicePool.name) # First, we try to assign from L2 cache if cacheL2 > 0: valid = None with transaction.atomic(): for n in servicePool.cachedUserServices().select_for_update().filter(userServiceManager().getCacheStateFilter(services.UserDeployment.L2_CACHE)).order_by('creation_date'): if n.needsOsManager(): if State.isUsable(n.state) is False or State.isUsable(n.os_state): valid = n break else: valid = n break if valid is not None: valid.moveToLevel(services.UserDeployment.L1_CACHE) return try: # This has a velid publication, or it will not be here userServiceManager().createCacheFor( typing.cast(ServicePoolPublication, servicePool.activePublication()), services.UserDeployment.L1_CACHE ) except MaxServicesReachedError: log.doLog(servicePool, log.ERROR, 'Max number of services reached for this service', log.INTERNAL) logger.warning('Max user services reached for %s: %s. Cache not created', servicePool.name, servicePool.max_srvs) except Exception: logger.exception('Exception')
def cancel(self) -> None: """ Asks the UserServiceManager to cancel the current operation of this user deployed service. """ from uds.core.managers import userServiceManager userServiceManager().cancel(self)
def getAndPushKey( self, userName: str, userService: 'models.UserService') -> typing.Tuple[str, str]: priv, pub = self.genKeyPairForSsh() authScript = self.getAuthorizeScript(userName, pub) userServiceManager().sendScript(userService, authScript) return priv, pub
def process(self, userService: 'UserService', message: str, data: typing.Any, options: typing.Optional[typing.Dict[str, typing.Any]] = None) -> str: """ 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 %s with params: %s, %s", userService, message, 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 message in ('ready', 'ip'): if not isinstance(data, dict): # Older actors?, previous to 2.5, convert it information.. data = { 'ips': [v.split('=') for v in typing.cast(str, data).split(',')], 'hostname': userService.friendly_name } # Old "info" state, will be removed in a near future if message == "info": ret = self.infoVal(userService) state = State.PREPARING elif message == "information": ret = self.infoValue(userService) state = State.PREPARING elif message == "log": self.doLog(userService, data, log.ACTOR) elif message == "login": self.loggedIn(userService, data) ip, hostname = userService.getConnectionSource() deadLine = userService.deployed_service.getDeadline() ret = "{}\t{}\t{}".format(ip, hostname, 0 if deadLine is None else deadLine) elif message == "logout": self.loggedOut(userService, data) doRemove = self.isRemovableOnLogout(userService) elif message == "ip": # This ocurss on main loop inside machine, so userService is usable state = State.USABLE self.notifyIp(userService.unique_id, userService, data) elif message == "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: userServiceManager().notifyReadyFromOsManager(userService, '') logger.debug('Returning %s', ret) return ret
def moveToLevel(self, cacheLevel: int) -> None: """ Moves cache items betwen levels, managed directly Args: cacheLevel: New cache level to put object in """ from uds.core.managers import userServiceManager userServiceManager().moveToLevel(self, cacheLevel)
def createFromAssignable(self, item: ServicePool) -> typing.Any: if 'user_id' not in self._params or 'assignable_id' not in self._params: return self.invalidRequestException('Invalid parameters') logger.debug('Creating from assignable: %s', self._params) userServiceManager().createFromAssignable( item, User.objects.get(uuid=processUuid(self._params['user_id'])), self._params['assignable_id']) return True
def run(self): with transaction.atomic(): removeFrom = getSqlDatetime() - timedelta(seconds=10) # We keep at least 10 seconds the machine before removing it, so we avoid connections errors removables = UserService.objects.filter(state=State.REMOVABLE, state_date__lt=removeFrom, deployed_service__service__provider__maintenance_mode=False)[0:UserServiceRemover.removeAtOnce] for us in removables: logger.debug('Checking removal of {}'.format(us)) try: if managers.userServiceManager().canRemoveServiceFromDeployedService(us.deployed_service) is True: managers.userServiceManager().remove(us) except Exception: logger.exception('Exception removing user service')
def desktopLogin(self, username: str, password: str, domain: str = '') -> None: script = '''import sys if sys.platform == 'win32': from uds import operations operations.writeToPipe("\\\\.\\pipe\\VDSMDPipe", struct.pack('!IsIs', 1, '{username}'.encode('utf8'), 2, '{password}'.encode('utf8')), True) '''.format(username=username, password=password) # Post script to service # operations.writeToPipe("\\\\.\\pipe\\VDSMDPipe", packet, True) dbService = self.dbservice() if dbService: managers.userServiceManager().sendScript(dbService, script)
def action(self) -> typing.MutableMapping[str, typing.Any]: """ BaseReady method expect a json POST with this fields: * token: str -> Valid Actor "own_token" (if invalid, will return an error). Currently it is the same as user service uuid, but this could change * secret: Secret for commsUrl for actor * ip: ip accesible by uds * port: port of the listener (normally 43910) This method will also regenerater the public-private key pair for client, that will be needed for the new ip Returns: { private_key: str -> Generated private key, PEM server_certificate: str -> Generated public key, PEM } """ logger.debug('Args: %s, Params: %s', self._args, self._params) userService = self.getUserService() # Stores known IP and notifies it to deployment userService.logIP(self._params['ip']) userServiceInstance = userService.getInstance() userServiceInstance.setIp(self._params['ip']) userService.updateData(userServiceInstance) # Store communications url also ActorV3Action.setCommsUrl(userService, self._params['ip'], int(self._params['port']), self._params['secret']) if userService.os_state != State.USABLE: userService.setOsState(State.USABLE) # Notify osManager or readyness if has os manager osManager = userService.getOsManagerInstance() if osManager: osManager.toReady(userService) userServiceManager().notifyReadyFromOsManager(userService, '') # Generates a certificate and send it to client. privateKey, cert, password = certs.selfSignedCert(self._params['ip']) # Store certificate with userService userService.setProperty('cert', cert) userService.setProperty('priv', privateKey) userService.setProperty('priv_passwd', password) return ActorV3Action.actorResult({ 'private_key': privateKey, 'server_certificate': cert, 'password': password })
def release(request, idService): logger.debug('ID Service: {}'.format(idService)) userService = userServiceManager().locateUserService(request.user, idService, create=False) logger.debug('UserSrvice: >{}<'.format(userService)) if userService is not None and userService.deployed_service.allow_users_remove: log.doLog( userService.deployed_service, log.INFO, "Removing User Service {} as requested by {} from {}".format(userService.friendly_name, request.user.pretty_name, request.ip), log.WEB ) userServiceManager().requestLogoff(userService) userService.release() return HttpResponseRedirect(reverse('Index'))
def growL2Cache(self, servicePool: ServicePool, cacheL1: int, cacheL2: int, assigned: int) -> None: """ Tries to grow L2 cache of service. If for some reason the number of deployed services (Counting all, ACTIVE and PREPARING, assigned, L1 and L2) is over max allowed service deployments, this method will not grow the L1 cache """ logger.debug("Growing L2 cache creating a new service for %s", servicePool.name) try: # This has a velid publication, or it will not be here userServiceManager().createCacheFor( typing.cast(ServicePoolPublication, servicePool.activePublication()), services.UserDeployment.L2_CACHE ) except MaxServicesReachedError: logger.warning('Max user services reached for %s: %s. Cache not created', servicePool.name, servicePool.max_srvs)
def script(self): idService = self._args[0] idTransport = self._args[1] scrambler = self._args[2] hostname = self._args[3] try: res = userServiceManager().getService(self._user, self._request.os, self._request.ip, idService, idTransport) logger.debug('Res: {}'.format(res)) ip, userService, userServiceInstance, transport, transportInstance = res password = cryptoManager().symDecrpyt(self.getValue('password'), scrambler) userService.setConnectionSource(self._request.ip, hostname) # Store where we are accessing from so we can notify Service transportScript = transportInstance.getEncodedTransportScript(userService, transport, ip, self._request.os, self._user, password, self._request) return Connection.result(result=transportScript) except ServiceNotReadyError as e: # Refresh ticket and make this retrayable return Connection.result(error=errors.SERVICE_IN_PREPARATION, errorCode=e.code, retryable=True) except Exception as e: logger.exception("Exception") return Connection.result(error=six.text_type(e)) return password
def reduceL1Cache(self, servicePool: ServicePool, cacheL1: int, cacheL2: int, assigned: int): logger.debug("Reducing L1 cache erasing a service in cache for %s", servicePool) # We will try to destroy the newest cacheL1 element that is USABLE if the deployer can't cancel a new service creation cacheItems: typing.List[UserService] = list( servicePool.cachedUserServices().filter( userServiceManager().getCacheStateFilter(services.UserDeployment.L1_CACHE) ).exclude( Q(properties__name='destroy_after') & Q(properties__value='y') ).order_by( '-creation_date' ).iterator() ) if not cacheItems: logger.debug('There is more services than max configured, but could not reduce cache L1 cause its already empty') return if cacheL2 < servicePool.cache_l2_srvs: valid = None for n in cacheItems: if n.needsOsManager(): if State.isUsable(n.state) is False or State.isUsable(n.os_state): valid = n break else: valid = n break if valid is not None: valid.moveToLevel(services.UserDeployment.L2_CACHE) return cache = cacheItems[0] cache.removeOrCancel()
def run(self) -> None: removeAtOnce: int = ( GlobalConfig.USER_SERVICE_CLEAN_NUMBER.getInt() ) # Same, it will work at reload with transaction.atomic(): removeFrom = getSqlDatetime() - timedelta( seconds=10 ) # We keep at least 10 seconds the machine before removing it, so we avoid connections errors removableUserServices: typing.Iterable[ UserService ] = UserService.objects.filter( state=State.REMOVABLE, state_date__lt=removeFrom, deployed_service__service__provider__maintenance_mode=False, )[ 0:removeAtOnce ].iterator() manager = managers.userServiceManager() for removableUserService in removableUserServices: logger.debug('Checking removal of %s', removableUserService.name) try: if ( manager.canRemoveServiceFromDeployedService( removableUserService.deployed_service ) is True ): manager.remove(removableUserService) except Exception: logger.exception('Exception removing user service')
def transportOwnLink(request: 'ExtendedHttpRequestWithUser', idService: str, idTransport: str): response: typing.MutableMapping[str, typing.Any] = {} # For type checkers to "be happy" try: res = userServiceManager().getService(request.user, request.os, request.ip, idService, idTransport) ip, userService, iads, trans, itrans = res # pylint: disable=unused-variable # This returns a response object in fact if itrans and ip: response = { 'url': itrans.getLink( userService, trans, ip, request.os, request.user, webPassword(request), request, ) } except ServiceNotReadyError as e: response = {'running': e.code * 25} except Exception as e: logger.exception("Exception") response = {'error': str(e)} return HttpResponse(content=json.dumps(response), content_type='application/json') # Will never reach this return errors.errorView(request, errors.UNKNOWN_ERROR)
def connection(self, doNotCheck=False): idService = self._args[0] idTransport = self._args[1] try: ip, userService, iads, trans, itrans = userServiceManager( ).getService( # pylint: disable=unused-variable self._user, self._request.os, self._request.ip, idService, idTransport, not doNotCheck) ci = { 'username': '', 'password': '', 'domain': '', 'protocol': 'unknown', 'ip': ip } if doNotCheck is False: ci.update( itrans.getConnectionInfo(userService, self._user, 'UNKNOWN')) return Connection.result(result=ci) except ServiceNotReadyError as e: # Refresh ticket and make this retrayable return Connection.result(error=errors.SERVICE_IN_PREPARATION, errorCode=e.code, retryable=True) except Exception as e: logger.exception("Exception") return Connection.result(error=str(e))
def isReady(self) -> bool: """ Returns if this service is ready (not preparing or marked for removal) """ # Call to isReady of the instance from uds.core.managers import userServiceManager return userServiceManager().isReady(self)
def release(request, idService): logger.debug('ID Service: {}'.format(idService)) userService = userServiceManager().locateUserService(request.user, idService, create=False) logger.debug('UserSrvice: >{}<'.format(userService)) if userService is not None and userService.deployed_service.allow_users_remove: log.doLog( userService.deployed_service, log.INFO, "Removing User Service {} as requested by {} from {}".format( userService.friendly_name, request.user.pretty_name, request.ip), log.WEB) userServiceManager().requestLogoff(userService) userService.release() return HttpResponseRedirect(reverse('Index'))
def script(self): idService = self._args[0] idTransport = self._args[1] scrambler = self._args[2] hostname = self._args[3] try: res = userServiceManager().getService(self._user, self._request.ip, idService, idTransport) logger.debug('Res: {}'.format(res)) ip, userService, userServiceInstance, transport, transportInstance = res password = cryptoManager().xor(self.getValue('password'), scrambler).decode('utf-8') userService.setConnectionSource(self._request.ip, hostname) # Store where we are accessing from so we can notify Service transportScript = transportInstance.getEncodedTransportScript(userService, transport, ip, self._request.os, self._user, password, self._request) return Connection.result(result=transportScript) except ServiceNotReadyError as e: # Refresh ticket and make this retrayable return Connection.result(error=errors.SERVICE_IN_PREPARATION, errorCode=e.code, retryable=True) except Exception as e: logger.exception("Exception") return Connection.result(error=six.text_type(e)) return password
def run(self): removeFrom = getSqlDatetime() - timedelta( seconds=10 ) # We keep at least 10 seconds the machine before removing it, so we avoid connections errors removables = UserService.objects.filter( state=State.REMOVABLE, state_date__lt=removeFrom, deployed_service__service__provider__maintenance_mode=False )[0:UserServiceRemover.removeAtOnce] for us in removables: try: if managers.userServiceManager( ).canRemoveServiceFromDeployedService( us.deployed_service) is True: managers.userServiceManager().remove(us) except Exception: logger.exception('Exception removing user service')
def enableService(request: 'ExtendedHttpRequestWithUser', idService: str, idTransport: str) -> typing.Mapping[str, typing.Any]: # Maybe we could even protect this even more by limiting referer to own server /? (just a meditation..) logger.debug('idService: %s, idTransport: %s', idService, idTransport) url = '' error = ugettext('Service not ready. Please, try again in a while.') # If meta service, process and rebuild idService & idTransport try: res = userServiceManager().getService(request.user, request.os, request.ip, idService, idTransport, doTest=False) scrambler = cryptoManager().randomString(32) password = cryptoManager().symCrypt(webPassword(request), scrambler) userService, trans = res[1], res[3] typeTrans = trans.getType() error = '' # No error if typeTrans.ownLink: url = reverse('TransportOwnLink', args=('A' + userService.uuid, trans.uuid)) else: data = { 'service': 'A' + userService.uuid, 'transport': trans.uuid, 'user': request.user.uuid, 'password': password } ticket = TicketStore.create(data) url = html.udsLink(request, ticket, scrambler) except ServiceNotReadyError as e: logger.debug('Service not ready') # Not ready, show message and return to this page in a while # error += ' (code {0:04X})'.format(e.code) error = ugettext( 'Your service is being created, please, wait for a few seconds while we complete it.)' ) + '({}%)'.format(int(e.code * 25)) except MaxServicesReachedError: logger.info('Number of service reached MAX for service pool "%s"', idService) error = errors.errorString(errors.MAX_SERVICES_REACHED) except ServiceAccessDeniedByCalendar: logger.info('Access tried to a calendar limited access pool "%s"', idService) error = errors.errorString(errors.SERVICE_CALENDAR_DENIED) except Exception as e: logger.exception('Error') error = str(e) return {'url': str(url), 'error': str(error)}
def reduceL2Cache(self, servicePool: ServicePool, cacheL1: int, cacheL2: int, assigned: int): logger.debug("Reducing L2 cache erasing a service in cache for %s", servicePool.name) if cacheL2 > 0: cacheItems: typing.List[UserService] = servicePool.cachedUserServices().filter( userServiceManager().getCacheStateFilter(services.UserDeployment.L2_CACHE) ).order_by('creation_date') # TODO: Look first for non finished cache items and cancel them? cache = cacheItems[0] cache.removeOrCancel()
def action(request: 'ExtendedHttpRequestWithUser', idService: str, actionString: str) -> HttpResponse: userService = userServiceManager().locateUserService(request.user, idService, create=False) response: typing.Any = None rebuild: bool = False if userService: if (actionString == 'release' and userService.deployed_service.allow_users_remove): rebuild = True log.doLog( userService.deployed_service, log.INFO, "Removing User Service {} as requested by {} from {}".format( userService.friendly_name, request.user.pretty_name, request.ip), log.WEB, ) userServiceManager().requestLogoff(userService) userService.release() elif (actionString == 'reset' and userService.deployed_service.allow_users_reset and userService.deployed_service.service.getType().canReset): rebuild = True log.doLog( userService.deployed_service, log.INFO, "Reseting User Service {} as requested by {} from {}".format( userService.friendly_name, request.user.pretty_name, request.ip), log.WEB, ) # userServiceManager().requestLogoff(userService) userServiceManager().reset(userService) if rebuild: # Rebuild services data, but return only "this" service for v in services.getServicesData(request)['services']: if v['id'] == idService: response = v break return HttpResponse(json.dumps(response), content_type="application/json")
def item_as_dict(self, item): # if item does not have an associated service, hide it (the case, for example, for a removed service) # Access from dict will raise an exception, and item will be skipped poolGroupId = None poolGroupName = _('Default') poolGroupThumb = DEFAULT_THUMB_BASE64 if item.servicesPoolGroup is not None: poolGroupId = item.servicesPoolGroup.uuid poolGroupName = item.servicesPoolGroup.name if item.servicesPoolGroup.image is not None: poolGroupThumb = item.servicesPoolGroup.image.thumb64 state = item.state if item.isInMaintenance(): state = State.MAINTENANCE elif userServiceManager().canInitiateServiceFromDeployedService(item) is False: state = State.SLOWED_DOWN val = { 'id': item.uuid, 'name': item.name, 'short_name': item.short_name, 'tags': [tag.tag for tag in item.tags.all()], 'parent': item.service.name, 'parent_type': item.service.data_type, 'comments': item.comments, 'state': state, 'thumb': item.image.thumb64 if item.image is not None else DEFAULT_THUMB_BASE64, 'account': item.account.name if item.account is not None else '', 'service_id': item.service.uuid, 'provider_id': item.service.provider.uuid, 'image_id': item.image.uuid if item.image is not None else None, 'servicesPoolGroup_id': poolGroupId, 'account_id': item.account.uuid if item.account is not None else None, 'pool_group_name': poolGroupName, 'pool_group_thumb': poolGroupThumb, 'initial_srvs': item.initial_srvs, 'cache_l1_srvs': item.cache_l1_srvs, 'cache_l2_srvs': item.cache_l2_srvs, 'max_srvs': item.max_srvs, 'user_services_count': item.userServices.exclude(state__in=State.INFO_STATES).count(), 'user_services_in_preparation': item.userServices.filter(state=State.PREPARING).count(), 'restrained': item.isRestrained(), 'show_transports': item.show_transports, 'visible': item.visible, 'allow_users_remove': item.allow_users_remove, 'ignores_unused': item.ignores_unused, 'fallbackAccess': item.fallbackAccess, 'permission': permissions.getEffectivePermission(self._user, item), 'info': Services.serviceInfo(item.service), } if item.osmanager is not None: val['osmanager_id'] = item.osmanager.uuid return val
def userServiceEnabler(request, idService, idTransport): # Maybe we could even protect this even more by limiting referer to own server /? (just a meditation..) logger.debug('idService: {}, idTransport: {}'.format( idService, idTransport)) url = '' error = _('Service not ready. Please, try again in a while.') # If meta service, process and rebuild idService & idTransport try: res = userServiceManager().getService(request.user, request.os, request.ip, idService, idTransport, doTest=False) scrambler = cryptoManager().randomString(32) password = cryptoManager().symCrypt(webPassword(request), scrambler) _x, userService, _x, trans, _x = res data = { 'service': 'A' + userService.uuid, 'transport': trans.uuid, 'user': request.user.uuid, 'password': password } ticket = TicketStore.create(data) error = '' url = html.udsLink(request, ticket, scrambler) except ServiceNotReadyError as e: logger.debug('Service not ready') # Not ready, show message and return to this page in a while error += ' (code {0:04X})'.format(e.code) except MaxServicesReachedError: logger.info( 'Number of service reached MAX for service pool "{}"'.format( idService)) error = errors.errorString(errors.MAX_SERVICES_REACHED) except ServiceAccessDeniedByCalendar: logger.info( 'Access tried to a calendar limited access pool "{}"'.format( idService)) error = errors.errorString(errors.SERVICE_CALENDAR_DENIED) except Exception as e: logger.exception('Error') error = str(e) return HttpResponse(json.dumps({ 'url': str(url), 'error': str(error) }), content_type='application/json')
def item_as_dict(self, item): # if item does not have an associated service, hide it (the case, for example, for a removed service) # Access from dict will raise an exception, and item will be skipped poolGroupId = None poolGroupName = _('Default') poolGroupThumb = DEFAULT_THUMB_BASE64 if item.servicesPoolGroup is not None: poolGroupId = item.servicesPoolGroup.uuid poolGroupName = item.servicesPoolGroup.name if item.servicesPoolGroup.image is not None: poolGroupThumb = item.servicesPoolGroup.image.thumb64 state = item.state if item.isInMaintenance(): state = State.MAINTENANCE elif userServiceManager().canInitiateServiceFromDeployedService(item) is False: state = State.SLOWED_DOWN val = { 'id': item.uuid, 'name': item.name, 'tags': [tag.tag for tag in item.tags.all()], 'parent': item.service.name, 'parent_type': item.service.data_type, 'comments': item.comments, 'state': state, 'thumb': item.image.thumb64 if item.image is not None else DEFAULT_THUMB_BASE64, 'account': item.account.name if item.account is not None else '', 'service_id': item.service.uuid, 'provider_id': item.service.provider.uuid, 'image_id': item.image.uuid if item.image is not None else None, 'servicesPoolGroup_id': poolGroupId, 'account_id': item.account.uuid if item.account is not None else None, 'pool_group_name': poolGroupName, 'pool_group_thumb': poolGroupThumb, 'initial_srvs': item.initial_srvs, 'cache_l1_srvs': item.cache_l1_srvs, 'cache_l2_srvs': item.cache_l2_srvs, 'max_srvs': item.max_srvs, 'user_services_count': item.userServices.count(), 'user_services_in_preparation': item.userServices.filter(state=State.PREPARING).count(), 'restrained': item.isRestrained(), 'show_transports': item.show_transports, 'visible': item.visible, 'fallbackAccess': item.fallbackAccess, 'permission': permissions.getEffectivePermission(self._user, item), 'info': Services.serviceInfo(item.service), } if item.osmanager is not None: val['osmanager_id'] = item.osmanager.uuid return val
def action(request, idService, action): logger.debug('ID Service: {}'.format(idService)) userService = userServiceManager().locateUserService(request.user, idService, create=False) logger.debug('UserService: >{}<'.format(userService)) response = None rebuild = False if userService: if action == 'release' and userService.deployed_service.allow_users_remove: rebuild = True log.doLog( userService.deployed_service, log.INFO, "Removing User Service {} as requested by {} from {}".format(userService.friendly_name, request.user.pretty_name, request.ip), log.WEB ) userServiceManager().requestLogoff(userService) userService.release() elif (action == 'reset' and userService.deployed_service.allow_users_reset and userService.deployed_service.service.getType().canReset): rebuild = True log.doLog( userService.deployed_service, log.INFO, "Reseting User Service {} as requested by {} from {}".format(userService.friendly_name, request.user.pretty_name, request.ip), log.WEB ) # userServiceManager().requestLogoff(userService) userServiceManager().reset(userService) if rebuild: # Rebuild services data, but return only "this" service for v in services.getServicesData(request)['services']: logger.debug('{} ==? {}'.format(v['id'], idService)) if v['id'] == idService: response = v break return HttpResponse(json.dumps(response), content_type="application/json")
def transportOwnLink(request, idService, idTransport): try: res = userServiceManager().getService(request.user, request.ip, idService, idTransport) ip, userService, iads, trans, itrans = res # @UnusedVariable # This returns a response object in fact return itrans.getLink(userService, trans, ip, request.os, request.user, webPassword(request), request) except ServiceNotReadyError as e: return errors.exceptionView(request, e) except Exception as e: logger.exception("Exception") return errors.exceptionView(request, e) # Will never reach this raise RuntimeError('Unreachable point reached!!!')
def transportOwnLink(request, idService, idTransport): try: res = userServiceManager().getService(request.user, request.os, request.ip, idService, idTransport) ip, userService, iads, trans, itrans = res # @UnusedVariable # This returns a response object in fact return itrans.getLink(userService, trans, ip, request.os, request.user, webPassword(request), request) except ServiceNotReadyError as e: return errors.exceptionView(request, e) except Exception as e: logger.exception("Exception") return errors.exceptionView(request, e) # Will never reach this raise RuntimeError('Unreachable point reached!!!')
def setInUse(self, inUse: bool) -> None: """ Set the "in_use" flag for this user deployed service Args: state: State to set to the "in_use" flag of this record :note: If the state is Fase (set to not in use), a check for removal of this deployed service is launched. """ from uds.core.managers import userServiceManager self.in_use = inUse self.in_use_date = getSqlDatetime() self.save(update_fields=['in_use', 'in_use_date']) # Start/stop accounting if inUse: self.startUsageAccounting() else: self.stopUsageAccounting() if not inUse: # Service released, check y we should mark it for removal # If our publication is not current, mark this for removal userServiceManager().checkForRemoval(self)
def action(request, idService, action): userService = userServiceManager().locateUserService(request.user, idService, create=False) response = None rebuild = False if userService: if action == 'release' and userService.deployed_service.allow_users_remove: rebuild = True log.doLog( userService.deployed_service, log.INFO, "Removing User Service {} as requested by {} from {}".format(userService.friendly_name, request.user.pretty_name, request.ip), log.WEB ) userServiceManager().requestLogoff(userService) userService.release() elif (action == 'reset' and userService.deployed_service.allow_users_reset and userService.deployed_service.service.getType().canReset): rebuild = True log.doLog( userService.deployed_service, log.INFO, "Reseting User Service {} as requested by {} from {}".format(userService.friendly_name, request.user.pretty_name, request.ip), log.WEB ) # userServiceManager().requestLogoff(userService) userServiceManager().reset(userService) if rebuild: # Rebuild services data, but return only "this" service for v in services.getServicesData(request)['services']: logger.debug('{} ==? {}'.format(v['id'], idService)) if v['id'] == idService: response = v break return HttpResponse(json.dumps(response), content_type="application/json")
def script(self): # Could be one-liner, (... = ..[0:4]), but mypy complains so this is fine :) idService = self._args[0] idTransport = self._args[1] scrambler = self._args[2] hostname = self._args[3] try: res = userServiceManager().getService( self._user, self._request.os, self._request.ip, idService, idTransport ) logger.debug('Res: %s', res) ( ip, userService, userServiceInstance, transport, transportInstance, ) = res # pylint: disable=unused-variable password = cryptoManager().symDecrpyt(self.getValue('password'), scrambler) userService.setConnectionSource( self._request.ip, hostname ) # Store where we are accessing from so we can notify Service if not ip: raise ServiceNotReadyError() transportScript = transportInstance.getEncodedTransportScript( userService, transport, ip, self._request.os, self._user, password, self._request, ) return Connection.result(result=transportScript) except ServiceNotReadyError as e: # Refresh ticket and make this retrayable return Connection.result( error=errors.SERVICE_IN_PREPARATION, errorCode=e.code, retryable=True ) except Exception as e: logger.exception("Exception") return Connection.result(error=str(e))
def userServiceEnabler(request, idService, idTransport): # Maybe we could even protect this even more by limiting referer to own server /? (just a meditation..) logger.debug('idService: {}, idTransport: {}'.format(idService, idTransport)) url = '' error = _('Service not ready. Please, try again in a while.') # If meta service, process and rebuild idService & idTransport try: res = userServiceManager().getService(request.user, request.os, request.ip, idService, idTransport, doTest=False) scrambler = cryptoManager().randomString(32) password = cryptoManager().symCrypt(webPassword(request), scrambler) _x, userService, _x, trans, _x = res data = { 'service': 'A' + userService.uuid, 'transport': trans.uuid, 'user': request.user.uuid, 'password': password } ticket = TicketStore.create(data) error = '' url = html.udsLink(request, ticket, scrambler) except ServiceNotReadyError as e: logger.debug('Service not ready') # Not ready, show message and return to this page in a while error += ' (code {0:04X})'.format(e.code) except MaxServicesReachedError: logger.info('Number of service reached MAX for service pool "{}"'.format(idService)) error = errors.errorString(errors.MAX_SERVICES_REACHED) except ServiceAccessDeniedByCalendar: logger.info('Access tried to a calendar limited access pool "{}"'.format(idService)) error = errors.errorString(errors.SERVICE_CALENDAR_DENIED) except Exception as e: logger.exception('Error') error = str(e) return HttpResponse( json.dumps({ 'url': str(url), 'error': str(error) }), content_type='application/json' )
def transportOwnLink(request: 'HttpRequest', idService: str, idTransport: str): try: res = userServiceManager().getService(request.user, request.os, request.ip, idService, idTransport) ip, userService, iads, trans, itrans = res # pylint: disable=unused-variable # This returns a response object in fact if itrans and ip: return itrans.getLink(userService, trans, ip, request.os, request.user, webPassword(request), request) except ServiceNotReadyError as e: return errors.exceptionView(request, e) except Exception as e: logger.exception("Exception") return errors.exceptionView(request, e) # Will never reach this return errors.errorView(request, errors.UNKNOWN_ERROR)
def transportOwnLink(request, idService, idTransport): try: res = userServiceManager().getService(request.user, request.ip, idService, idTransport) ip, userService, iads, trans, itrans = res # @UnusedVariable # This returns a response object in fact return itrans.getLink(userService, trans, ip, request.os, request.user, webPassword(request), request) except ServiceNotReadyError as e: return render(request, theme.template('service_not_ready.html'), { 'fromLauncher': False, 'code': e.code }) except Exception as e: logger.exception("Exception") return errors.exceptionView(request, e) # Will never reach this raise RuntimeError('Unreachable point reached!!!')
def transportOwnLink(request, idService, idTransport): try: res = userServiceManager().getService(request.user, request.ip, idService, idTransport) ip, userService, iads, trans, itrans = res # @UnusedVariable # This returns a response object in fact return itrans.getLink(userService, trans, ip, request.os, request.user, webPassword(request), request) except ServiceNotReadyError as e: return render(request, theme.template('service_not_ready.html'), { 'fromLauncher': False, 'code': e.code } ) except Exception as e: logger.exception("Exception") return errors.exceptionView(request, e) # Will never reach this raise RuntimeError('Unreachable point reached!!!')
def connection(self, doNotCheck=False): idService = self._args[0] idTransport = self._args[1] try: ip, userService, iads, trans, itrans = userServiceManager().getService(self._user, self._request.ip, idService, idTransport, not doNotCheck) ci = { 'username': '', 'password': '', 'domain': '', 'protocol': 'unknown', 'ip': ip } if doNotCheck is False: ci.update(itrans.getConnectionInfo(userService, self._user, 'UNKNOWN')) return Connection.result(result=ci) except ServiceNotReadyError as e: # Refresh ticket and make this retrayable return Connection.result(error=errors.SERVICE_IN_PREPARATION, errorCode=e.code, retryable=True) except Exception as e: logger.exception("Exception") return Connection.result(error=six.text_type(e))
def userServiceStatus(request: 'ExtendedHttpRequestWithUser', idService: str, idTransport: str) -> HttpResponse: ''' Returns; 'running' if not ready 'ready' if is ready but not accesed by client 'accessed' if ready and accesed by UDS client Note: ''' ip: typing.Union[str, None, bool] userService = None try: ( ip, userService, userServiceInstance, transport, transportInstance, ) = userServiceManager().getService(request.user, request.os, request.ip, idService, idTransport, doTest=True) # logger.debug('Res: %s %s %s %s %s', ip, userService, userServiceInstance, transport, transportInstance) except ServiceNotReadyError: ip = None except Exception as e: ip = False ready = 'ready' if userService and userService.getProperty('accessedByClient') != '0': ready = 'accessed' status = 'running' if ip is None else 'error' if ip is False else ready return HttpResponse(json.dumps({'status': status}), content_type='application/json')
def clientEnabler(request, idService, idTransport): # Maybe we could even protect this even more by limiting referer to own server /? (just a meditation..) logger.debug('idService: {}, idTransport: {}'.format(idService, idTransport)) url = '' error = _('Service not ready. Please, try again in a while.') try: res = userServiceManager().getService(request.user, request.ip, idService, idTransport, doTest=False) scrambler = cryptoManager().randomString(32) password = cryptoManager().xor(webPassword(request), scrambler) _x, userService, _x, trans, _x = res data = { 'service': 'A' + userService.uuid, 'transport': trans.uuid, 'user': request.user.uuid, 'password': password } ticket = TicketStore.create(data) error = '' url = html.udsLink(request, ticket, scrambler) except ServiceNotReadyError as e: logger.debug('Service not ready') # Not ready, show message and return to this page in a while error += ' (code {0:04X})'.format(e.code) except MaxServicesReachedError: logger.info('Number of service reached MAX for service pool "{}"'.format(idService)) error = errors.errorString(errors.MAX_SERVICES_REACHED) except Exception as e: logger.exception('Error') error = six.text_type(e) return HttpResponse( '{{ "url": "{}", "error": "{}" }}'.format(url, error), content_type='application/json' )
def ticketAuth(request, ticketId): """ Used to authenticate an user via a ticket """ try: data = TicketStore.get(ticketId, invalidate=True) try: # Extract ticket.data from ticket.data storage, and remove it if success username = data['username'] groups = data['groups'] auth = data['auth'] realname = data['realname'] servicePool = data['servicePool'] password = data['password'] transport = data['transport'] except Exception: logger.error('Ticket stored is not valid') raise InvalidUserException() auth = Authenticator.objects.get(uuid=auth) # If user does not exists in DB, create it right now # Add user to groups, if they exists... grps = [] for g in groups: try: grps.append(auth.groups.get(uuid=g)) except Exception: logger.debug('Group list has changed since ticket assignment') if len(grps) == 0: logger.error('Ticket has no valid groups') raise Exception('Invalid ticket authentication') usr = auth.getOrCreateUser(username, realname) if usr is None or State.isActive(usr.state) is False: # If user is inactive, raise an exception raise InvalidUserException() # Add groups to user (replace existing groups) usr.groups.set(grps) # Force cookie generation webLogin(request, None, usr, password) request.user = usr # Temporarily store this user as "authenticated" user, next requests will be done using session request.session['ticket'] = '1' # Store that user access is done using ticket logger.debug("Service & transport: {}, {}".format(servicePool, transport)) for v in DeployedService.objects.all(): logger.debug("{} {}".format(v.uuid, v.name)) # Check if servicePool is part of the ticket if servicePool is not None: # If service pool is in there, also is transport res = userServiceManager().getService(request.user, request.ip, 'F' + servicePool, transport, False) _x, userService, _x, transport, _x = res transportInstance = transport.getInstance() if transportInstance.ownLink is True: link = reverse('TransportOwnLink', args=('A' + userService.uuid, transport.uuid)) else: link = html.udsAccessLink(request, 'A' + userService.uuid, transport.uuid) response = render( request, theme.template('simpleLauncher.html'), { 'link': link } ) else: response = HttpResponsePermanentRedirect(reverse('uds.web.views.index')) # Now ensure uds cookie is at response getUDSCookie(request, response, True) return response except ServiceNotReadyError as e: return render( request, theme.template('service_not_ready.html'), { 'fromLauncher': True, 'code': e.code } ) except TicketStore.InvalidTicket: return render( request, theme.template('simpleLauncherAlreadyLaunched.html') ) except Authenticator.DoesNotExist: logger.error('Ticket has an non existing authenticator') return errors.exceptionView(request, InvalidUserException()) except DeployedService.DoesNotExist: logger.error('Ticket has an invalid Service Pool') return errors.exceptionView(request, InvalidServiceException()) except Exception as e: logger.exception('Exception') return errors.exceptionView(request, e)
def get(self): ''' Processes get requests ''' logger.debug("Client args for GET: {0}".format(self._args)) if len(self._args) == 0: # Gets version url = self._request.build_absolute_uri(reverse('ClientDownload')) return Client.result({ 'availableVersion': CLIENT_VERSION, 'requiredVersion': REQUIRED_CLIENT_VERSION, 'downloadUrl': url }) if len(self._args) == 1: # Simple test return Client.result(_('Correct')) try: ticket, scrambler = self._args # If more than 2 args, got an error hostname = self._params['hostname'] # Or if hostname is not included... srcIp = self._request.ip # Ip is optional, if GlobalConfig.HONOR_CLIENT_IP_NOTIFY.getBool() is True: srcIp = self._params.get('ip', srcIp) except Exception: raise RequestError('Invalid request') logger.debug('Got Ticket: {}, scrambled: {}, Hostname: {}, Ip: {}'.format(ticket, scrambler, hostname, srcIp)) try: data = TicketStore.get(ticket) except Exception: return Client.result(error=errors.ACCESS_DENIED) self._request.user = User.objects.get(uuid=data['user']) try: logger.debug(data) res = userServiceManager().getService(self._request.user, self._request.ip, data['service'], data['transport']) logger.debug('Res: {}'.format(res)) ip, userService, userServiceInstance, transport, transportInstance = res password = cryptoManager().xor(data['password'], scrambler).decode('utf-8') userService.setConnectionSource(srcIp, hostname) # Store where we are accessing from so we can notify Service transportScript = transportInstance.getUDSTransportScript(userService, transport, ip, self._request.os, self._request.user, password, self._request) logger.debug('Script:\n{}'.format(transportScript)) return Client.result(result=transportScript.encode('bz2').encode('base64')) except ServiceNotReadyError as e: # Refresh ticket and make this retrayable TicketStore.revalidate(ticket, 20) # Retry will be in at most 5 seconds return Client.result(error=errors.SERVICE_IN_PREPARATION, errorCode=e.code, retryable=True) except Exception as e: logger.exception("Exception") return Client.result(error=six.text_type(e)) # Will never reach this raise RuntimeError('Unreachable point reached!!!')
def ticketAuth(request: 'HttpRequest', ticketId: str) -> HttpResponse: # pylint: disable=too-many-locals,too-many-branches,too-many-statements """ Used to authenticate an user via a ticket """ try: data = TicketStore.get(ticketId, invalidate=True) try: # Extract ticket.data from ticket.data storage, and remove it if success username = data['username'] groups = data['groups'] auth = data['auth'] realname = data['realname'] servicePool = data['servicePool'] password = cryptoManager().decrypt(data['password']) transport = data['transport'] except Exception: logger.error('Ticket stored is not valid') raise auths.exceptions.InvalidUserException() auth = Authenticator.objects.get(uuid=auth) # If user does not exists in DB, create it right now # Add user to groups, if they exists... grps: typing.List = [] for g in groups: try: grps.append(auth.groups.get(uuid=g)) except Exception: logger.debug('Group list has changed since ticket assignment') if not grps: logger.error('Ticket has no valid groups') raise Exception('Invalid ticket authentication') usr = auth.getOrCreateUser(username, realname) if usr is None or State.isActive( usr.state) is False: # If user is inactive, raise an exception raise auths.exceptions.InvalidUserException() # Add groups to user (replace existing groups) usr.groups.set(grps) # Force cookie generation webLogin(request, None, usr, password) request.user = usr # Temporarily store this user as "authenticated" user, next requests will be done using session request.session[ 'ticket'] = '1' # Store that user access is done using ticket # Override and recalc transport based on current os transport = None logger.debug("Service & transport: %s, %s", servicePool, transport) # Check if servicePool is part of the ticket if servicePool: # If service pool is in there, also is transport res = userServiceManager().getService(request.user, request.os, request.ip, 'F' + servicePool, transport, False) _, userService, _, transport, _ = res transportInstance = transport.getInstance() if transportInstance.ownLink is True: link = reverse('TransportOwnLink', args=('A' + userService.uuid, transport.uuid)) else: link = html.udsAccessLink(request, 'A' + userService.uuid, transport.uuid) request.session['launch'] = link response = HttpResponseRedirect(reverse('page.ticket.launcher')) else: response = HttpResponseRedirect(reverse('page.index')) # Now ensure uds cookie is at response getUDSCookie(request, response, True) return response except ServiceNotReadyError as e: return errors.errorView(request, errors.SERVICE_NOT_READY) except TicketStore.InvalidTicket: return errors.errorView(request, errors.RELOAD_NOT_SUPPORTED) except Authenticator.DoesNotExist: logger.error('Ticket has an non existing authenticator') return errors.errorView(request, errors.ACCESS_DENIED) except ServicePool.DoesNotExist: logger.error('Ticket has an invalid Service Pool') return errors.errorView(request, errors.SERVICE_NOT_FOUND) except Exception as e: logger.exception('Exception') return errors.exceptionView(request, e)
def serviceList(self): # We look for services for this authenticator groups. User is logged in in just 1 authenticator, so his groups must coincide with those assigned to ds groups = list(self._user.getGroups()) availServices = DeployedService.getDeployedServicesForGroups(groups) availUserServices = UserService.getUserAssignedServices(self._user) # Extract required data to show to user services = [] # Select assigned user services for svr in availUserServices: # Skip maintenance services... trans = [] for t in svr.transports.all().order_by('priority'): if t.validForIp(self._request.ip) and t.getType().providesConnetionInfo(): trans.append({'id': t.uuid, 'name': t.name}) servicePool = svr.deployed_service services.append({'id': 'A' + svr.uuid, 'name': servicePool.name, 'description': servicePool.comments, 'visual_name': servicePool.visual_name, 'group': servicePool.servicesPoolGroup if servicePool.servicesPoolGroup is not None else ServicesPoolGroup.default().as_dict, 'thumb': servicePool.image.thumb64 if servicePool.image is not None else DEFAULT_THUMB_BASE64, 'show_transports': servicePool.show_transports, 'allow_users_remove': servicePool.allow_users_remove, 'maintenance': servicePool.isInMaintenance(), 'not_accesible': not servicePool.isAccessAllowed(), 'to_be_replaced': False, # Manually assigned will not be autoremoved never 'transports': trans, 'maintenance': servicePool.isInMaintenance(), 'in_use': servicePool.in_use}) logger.debug(services) # Now generic user service for servicePool in availServices: trans = [] for t in servicePool.transports.all().order_by('priority'): if t.validForIp(self._request.ip) and t.getType().providesConnetionInfo(): trans.append({'id': t.uuid, 'name': t.name}) # Locate if user service has any already assigned user service for this ads = userServiceManager().getExistingAssignationForUser(servicePool, self._user) if ads is None: in_use = False else: in_use = ads.in_use services.append({'id': 'F' + servicePool.uuid, 'name': servicePool.name, 'description': servicePool.comments, 'visual_name': servicePool.visual_name, 'group': servicePool.servicesPoolGroup if servicePool.servicesPoolGroup is not None else ServicesPoolGroup.default().as_dict, 'thumb': servicePool.image.thumb64 if servicePool.image is not None else DEFAULT_THUMB_BASE64, 'show_transports': servicePool.show_transports, 'allow_users_remove': servicePool.allow_users_remove, 'maintenance': servicePool.isInMaintenance(), 'not_accesible': not servicePool.isAccessAllowed(), 'to_be_replaced': servicePool.toBeReplaced(), 'transports': trans, 'maintenance': servicePool.isInMaintenance(), 'in_use': in_use}) logger.debug('Services: {0}'.format(services)) services = sorted(services, key=lambda s: s['name'].upper()) return Connection.result(result=services)
def getAndPushKey(self, user, userService): priv, pub = self.genKeyPairForSsh() authScript = self.getAuthorizeScript(user, pub) userServiceManager().sendScript(userService, authScript) return priv, pub