Merge remote-tracking branch 'origin/v3.5' into v3.6

This commit is contained in:
Adolfo Gómez García 2022-08-04 21:56:39 +02:00
commit e79753748e
6 changed files with 54 additions and 23 deletions

View File

@ -198,7 +198,7 @@ class UDSActorClient(threading.Thread): # pylint: disable=too-many-instance-att
time.sleep(1.3) # Sleeps between loop iterations time.sleep(1.3) # Sleeps between loop iterations
self._loginInfo = None self._loginInfo = None
self.api.logout(platform.operations.getCurrentUser() + self._extraLogoff) self.api.logout(platform.operations.getCurrentUser() + self._extraLogoff, platform.operations.getSessionType())
except Exception as e: except Exception as e:
logger.error('Error on client loop: %s', e) logger.error('Error on client loop: %s', e)

View File

@ -131,7 +131,7 @@ class UDSApi: # pylint: disable=too-few-public-methods
headers=headers, headers=headers,
verify=self._validateCert, verify=self._validateCert,
timeout=TIMEOUT, timeout=TIMEOUT,
proxies=NO_PROXY # type: ignore proxies=NO_PROXY # type: ignore
if disableProxy if disableProxy
else None, # if not proxies wanted, enforce it else None, # if not proxies wanted, enforce it
) )
@ -351,19 +351,21 @@ class UDSServerApi(UDSApi):
actor_type: typing.Optional[str], actor_type: typing.Optional[str],
token: str, token: str,
username: str, username: str,
sessionType: str,
interfaces: typing.Iterable[types.InterfaceInfoType], interfaces: typing.Iterable[types.InterfaceInfoType],
secret: typing.Optional[str], secret: typing.Optional[str],
) -> None: ) -> typing.Optional[str]:
if not token: if not token:
return return None
payload = { payload = {
'type': actor_type or types.MANAGED, 'type': actor_type or types.MANAGED,
'id': [{'mac': i.mac, 'ip': i.ip} for i in interfaces], 'id': [{'mac': i.mac, 'ip': i.ip} for i in interfaces],
'token': token, 'token': token,
'username': username, 'username': username,
'session_type': sessionType,
'secret': secret or '', 'secret': secret or '',
} }
self._doPost('logout', payload) return self._doPost('logout', payload) # Can be 'ok' or 'notified'
def log(self, own_token: str, level: int, message: str) -> None: def log(self, own_token: str, level: int, message: str) -> None:
if not own_token: if not own_token:
@ -418,8 +420,11 @@ class UDSClientApi(UDSApi):
max_idle=result['max_idle'], max_idle=result['max_idle'],
) )
def logout(self, username: str) -> None: def logout(self, username: str, sessionType: typing.Optional[str]) -> None:
payLoad = {'username': username} payLoad = {
'username': username,
'session_type': sessionType or UNKNOWN
}
self.post('logout', payLoad) self.post('logout', payLoad)
def ping(self) -> bool: def ping(self) -> bool:

View File

@ -377,6 +377,7 @@ class CommonService: # pylint: disable=too-many-instance-attributes
self._cfg.actorType, self._cfg.actorType,
self._cfg.own_token, self._cfg.own_token,
'', '',
'',
self._interfaces, self._interfaces,
self._secret, self._secret,
) )
@ -494,9 +495,12 @@ class CommonService: # pylint: disable=too-many-instance-attributes
# If unmanaged, do initialization now, because we don't know before this # If unmanaged, do initialization now, because we don't know before this
# Also, even if not initialized, get a "login" notification token # Also, even if not initialized, get a "login" notification token
if not self.isManaged(): if not self.isManaged():
self.initialize() self._initialized = (
master_token = self._cfg.master_token self.initialize()
secret = self._secret ) # Maybe it's a local login by an unmanaged host.... On real login, will execute initilize again
if self._initialized:
master_token = self._cfg.master_token
secret = self._secret
# Own token will not be set if UDS did not assigned the initialized VM to an user # Own token will not be set if UDS did not assigned the initialized VM to an user
# In that case, take master token (if machine is Unamanaged version) # In that case, take master token (if machine is Unamanaged version)
@ -518,7 +522,7 @@ class CommonService: # pylint: disable=too-many-instance-attributes
return result return result
def logout(self, username: str) -> None: def logout(self, username: str, sessionType: typing.Optional[str] = None) -> None:
self._loggedIn = False self._loggedIn = False
master_token = self._cfg.master_token master_token = self._cfg.master_token
@ -527,9 +531,20 @@ class CommonService: # pylint: disable=too-many-instance-attributes
# In that case, take master token (if machine is Unamanaged version) # In that case, take master token (if machine is Unamanaged version)
token = self._cfg.own_token or master_token token = self._cfg.own_token or master_token
if token: if token:
self._api.logout( # If logout is not processed (that is, not ok result), the logout has not been processed
self._cfg.actorType, token, username, self._interfaces, self._secret if (
) self._api.logout(
self._cfg.actorType,
token,
username,
sessionType or '',
self._interfaces,
self._secret,
)
!= 'ok'
):
logger.info('Logout from %s ignored as required by uds broker', username)
return
self.onLogout(username) self.onLogout(username)

View File

@ -419,7 +419,7 @@ class Version(ActorV3Action):
class LoginLogout(ActorV3Action): class LoginLogout(ActorV3Action):
name = 'notused' # Not really important, this is not a "leaf" class and will not be directly available name = 'notused' # Not really important, this is not a "leaf" class and will not be directly available
def notifyService(self, isLogin: bool): def notifyService(self, isLogin: bool) -> None:
try: try:
# If unmanaged, use Service locator # If unmanaged, use Service locator
service: 'services.Service' = Service.objects.get( service: 'services.Service' = Service.objects.get(
@ -446,12 +446,12 @@ class LoginLogout(ActorV3Action):
# idInfo = service.recoverIdInfo(validId) # idInfo = service.recoverIdInfo(validId)
# Notify Service that someone logged in/out # Notify Service that someone logged in/out
is_remote = self._params.get('session_type', '')[:4] in ('xrdp', 'RDP-')
if isLogin: if isLogin:
# Try to guess if this is a remote session # 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) service.processLogin(validId, remote_login=is_remote)
else: else:
service.processLogout(validId) service.processLogout(validId, remote_login=is_remote)
# All right, service notified... # All right, service notified...
except Exception: except Exception:
@ -562,6 +562,7 @@ class Logout(LoginLogout):
if isManaged: if isManaged:
raise raise
self.notifyService(isLogin=False) # Logout notification self.notifyService(isLogin=False) # Logout notification
return ActorV3Action.actorResult('notified') # Result is that we have not processed the logout in fact, but notified the service
return ActorV3Action.actorResult('ok') return ActorV3Action.actorResult('ok')

View File

@ -335,7 +335,7 @@ class Service(Module):
""" """
return return
def processLogout(self, id: str) -> None: def processLogout(self, id: str, remote_login: bool) -> None:
""" """
In the case that a logout 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) an service token, this method will be called with provided info by uds actor (parameters)

View File

@ -231,10 +231,13 @@ class IPMachinesService(IPServiceBase):
# Sets maximum services for this # Sets maximum services for this
self.maxDeployed = len(self._ips) self.maxDeployed = len(self._ips)
def canBeUsed(self, locked: typing.Optional[int], now: int) -> int: def canBeUsed(self, locked: typing.Optional[typing.Union[str, int]], now: int) -> int:
# If _maxSessionForMachine is 0, it can be used only if not locked # If _maxSessionForMachine is 0, it can be used only if not locked
# (that is locked is None) # (that is locked is None)
locked = locked or 0 locked = locked or 0
if isinstance(locked, str) and not '.' in locked: # Convert to int and treat it as a "locked" element
locked = int(locked)
if self._maxSessionForMachine <= 0: if self._maxSessionForMachine <= 0:
return not bool(locked) # If locked is None, it can be used return not bool(locked) # If locked is None, it can be used
@ -342,19 +345,26 @@ class IPMachinesService(IPServiceBase):
Process login for a machine not assigned to any user. Process login for a machine not assigned to any user.
''' '''
logger.debug('Processing login for %s: %s', self, id) logger.debug('Processing login for %s: %s', self, id)
# Locate the IP on the storage # Locate the IP on the storage
theIP = IPServiceBase.getIp(id) theIP = IPServiceBase.getIp(id)
now = getSqlDatetimeAsUnix() now = getSqlDatetimeAsUnix()
locked = self.storage.getPickle(theIP) locked: typing.Union[None, str, int] = self.storage.getPickle(theIP)
if self.canBeUsed(locked, now): if self.canBeUsed(locked, now):
self.storage.putPickle(theIP, now) # Lock it self.storage.putPickle(theIP, str(now)) # Lock it
def processLogout(self, id: str) -> None: def processLogout(self, id: str, remote_login: bool) -> None:
''' '''
Process logout for a machine not assigned to any user. Process logout for a machine not assigned to any user.
''' '''
logger.debug('Processing logout for %s: %s', self, id) logger.debug('Processing logout for %s: %s', self, id)
self.unassignMachine(id) # Locate the IP on the storage
theIP = IPServiceBase.getIp(id)
locked: typing.Union[None, str, int] = self.storage.getPickle(theIP)
# If locked is str, has been locked by processLogin so we can unlock it
if isinstance(locked, str):
self.unassignMachine(id)
# If not proccesed by login, we cannot release it
def notifyInitialization(self, id: str) -> None: def notifyInitialization(self, id: str) -> None:
''' '''