diff --git a/client-py3/full/linux/udsclient-appimage-x86_64.recipe b/client-py3/full/linux/udsclient-appimage-x86_64.recipe index c2f498db..eb7559ba 100644 --- a/client-py3/full/linux/udsclient-appimage-x86_64.recipe +++ b/client-py3/full/linux/udsclient-appimage-x86_64.recipe @@ -31,7 +31,7 @@ AppDir: arch: amd64 sources: - sourceline: 'deb [arch=amd64] http://ftp.de.debian.org/debian/ bullseye main contrib non-free' - key_url: 'http://keyserver.ubuntu.com/pks/lookup?op=get&search=0x04EE7237B7D453EC' + key_url: 'http://keyserver.ubuntu.com/pks/lookup?op=get&search=0x648ACFD622F3D138' include: - python3 diff --git a/client-py3/full/src/uds/rest.py b/client-py3/full/src/uds/rest.py index 62eaf11e..f544cab2 100644 --- a/client-py3/full/src/uds/rest.py +++ b/client-py3/full/src/uds/rest.py @@ -183,7 +183,6 @@ class RestApi: def _open( url: str, certErrorCallback: typing.Optional[CertCallbackType] = None ) -> typing.Any: - print('Open') ctx = ssl.create_default_context() ctx.check_hostname = False ctx.verify_mode = ssl.CERT_NONE @@ -246,7 +245,6 @@ class RestApi: def getUrl( url: str, certErrorCallback: typing.Optional[CertCallbackType] = None ) -> bytes: - print(url) with RestApi._open(url, certErrorCallback) as response: resp = response.read() diff --git a/server/src/uds/REST/methods/actor_v3.py b/server/src/uds/REST/methods/actor_v3.py index 269ad0ef..7eaaf483 100644 --- a/server/src/uds/REST/methods/actor_v3.py +++ b/server/src/uds/REST/methods/actor_v3.py @@ -269,24 +269,6 @@ class Initialize(ActorV3Action): state__in=[State.USABLE, State.PREPARING], ) - # If no UserService exists, - # is managed (service exists), then it's a "local login" - if not dbFilter.exists() and service: - # The userService does not exists, try to lock the id on the service - serviceInstance = service.getInstance() - lockedId = serviceInstance.lockId(idsList) - if lockedId: - # Return an "generic" result allowing login/logout processing - return ActorV3Action.actorResult( - { - 'own_token': self._params['token'], - 'unique_id': lockedId, - 'os': None, - } - ) - else: # if no lock, return empty result - raise Exception() # Unmanaged host - userService: UserService = next( iter( dbFilter.filter( @@ -442,7 +424,7 @@ class Version(ActorV3Action): class LoginLogout(ActorV3Action): name = 'notused' # Not really important, this is not a "leaf" class and will not be directly available - def notifyService(self, login: bool): + def notifyService(self, isLogin: bool): try: # If unmanaged, use Service locator service: 'services.Service' = Service.objects.get( @@ -462,9 +444,11 @@ class LoginLogout(ActorV3Action): if not validId: raise Exception() + # Recover Id Info from service and validId + # idInfo = service.recoverIdInfo(validId) # Notify Service that someone logged in/out - if login: + if isLogin: # Try to guess if this is a remote session is_remote = self._params.get('session_type', '')[:4] in ('xrdp', 'RDP-') service.processLogin(validId, remote_login=is_remote) @@ -536,7 +520,7 @@ class Login(LoginLogout): except Exception: # If unamanaged host, lest do a bit more work looking for a service with the provided parameters... if isManaged: raise - self.notifyService(login=True) + self.notifyService(isLogin=True) return ActorV3Action.actorResult( {'ip': ip, 'hostname': hostname, 'dead_line': deadLine, 'max_idle': maxIdle} @@ -579,7 +563,7 @@ class Logout(LoginLogout): except Exception: # If unamanaged host, lest do a bit more work looking for a service with the provided parameters... if isManaged: raise - self.notifyService(login=False) # Logout notification + self.notifyService(isLogin=False) # Logout notification return ActorV3Action.actorResult('ok') @@ -663,6 +647,28 @@ class Unmanaged(ActorV3Action): x['mac'] for x in self._params['id'] ][:10] validId: typing.Optional[str] = service.getValidId(idsList) + + # Check if there is already an assigned user service + # To notify it logout + userService: typing.Optional[UserService] + try: + dbFilter = UserService.objects.filter( + unique_id__in=idsList, + state__in=[State.USABLE, State.PREPARING], + ) + + userService = next( + iter( + dbFilter.filter( + unique_id__in=idsList, + state__in=[State.USABLE, State.PREPARING], + ) + ) + ) + except StopIteration: + userService = None + + # Try to infer the ip from the valid id (that could be an IP or a MAC) ip: str try: ip = next( @@ -681,8 +687,12 @@ class Unmanaged(ActorV3Action): 'password': password, } if validId: - # Notify service of it "just start" action - service.notifyInitialization(validId) + # If id is assigned to an user service, notify "logout" to it + if userService: + Logout.process_logout(userService, 'init') + else: + # If it is not assgined to an user service, notify service + service.notifyInitialization(validId) # Store certificate, secret & port with service if validId service.storeIdInfo( diff --git a/server/src/uds/core/services/service.py b/server/src/uds/core/services/service.py index aacca5fe..842629aa 100644 --- a/server/src/uds/core/services/service.py +++ b/server/src/uds/core/services/service.py @@ -322,22 +322,12 @@ class Service(Module): """ return None - def lockId(self, id: typing.List[str]) -> typing.Optional[str]: - """ - Locks the id, so it cannot be used by a service pool. - - Args: - id (typing.List[str]): Id to lock (list of possible ids) - - Returns: - str: Valid id of locked element, or None if no id found - """ - return None - def processLogin(self, id: str, remote_login: bool) -> None: """ In the case that a login is invoked directly on an actor controlled machine with an service token, this method will be called with provided info by uds actor (parameters) + That is, this method will only be called it UDS does not recognize the invoker, but the invoker + has a valid token and the service has recognized it. (via getValidId) Args: id (str): Id validated through "getValidId" @@ -347,12 +337,13 @@ class Service(Module): def processLogout(self, id: str) -> None: """ - In the case that a login is invoked directly on an actor controlled machine with + In the case that a logout is invoked directly on an actor controlled machine with an service token, this method will be called with provided info by uds actor (parameters) + That is, this method will only be called it UDS does not recognize the invoker, but the invoker + has a valid token and the service has recognized it. (via getValidId) Args: id (str): Id validated through "getValidId" - remote_login (bool): if the login seems to be a remote login """ return @@ -364,6 +355,7 @@ class Service(Module): Args: id (str): Id validated through "getValidId" """ + return def storeIdInfo(self, id: str, data: typing.Any) -> None: self.storage.putPickle('__nfo_' + id, data) diff --git a/server/src/uds/services/PhysicalMachines/service_multi.py b/server/src/uds/services/PhysicalMachines/service_multi.py index 02e4ba84..dc931ec2 100644 --- a/server/src/uds/services/PhysicalMachines/service_multi.py +++ b/server/src/uds/services/PhysicalMachines/service_multi.py @@ -339,7 +339,10 @@ class IPMachinesService(IPServiceBase): return userServiceInstance.error('IP already assigned') def processLogin(self, id: str, remote_login: bool) -> None: - logger.info('Processing login for %s', id) + ''' + Process login for a machine not assigned to any user. + ''' + logger.debug('Processing login for %s: %s', self, id) # Locate the IP on the storage theIP = IPServiceBase.getIp(id) now = getSqlDatetimeAsUnix() @@ -348,7 +351,18 @@ class IPMachinesService(IPServiceBase): self.storage.putPickle(id, now) # Lock it def processLogout(self, id: str) -> None: - logger.info('Processing logout for %s', id) + ''' + Process logout for a machine not assigned to any user. + ''' + logger.debug('Processing logout for %s: %s', self, id) + self.unassignMachine(id) + + def notifyInitialization(self, id: str) -> None: + ''' + Notify that a machine has been initialized. + Normally, this means that + ''' + logger.debug('Notify initialization for %s: %s', self, id) self.unassignMachine(id) def getValidId(self, idsList: typing.Iterable[str]) -> typing.Optional[str]: