advancing on new v3 actor

This commit is contained in:
Adolfo Gómez García 2019-11-30 22:34:05 +01:00
parent a8b94325e5
commit ced7226f81
11 changed files with 214 additions and 170 deletions

View File

@ -72,7 +72,7 @@ class PublicProvider(handler.Handler):
logger.debug('Received Pre connection') logger.debug('Received Pre connection')
if 'user' not in self._params or 'protocol' not in self._params: if 'user' not in self._params or 'protocol' not in self._params:
raise Exception('Invalid preConnect parameters') raise Exception('Invalid preConnect parameters')
return self._service.preConnect(self._params['user'], self._params['protocol']) return self._service.preConnect(self._params['user'], self._params['protocol'], self._params.get('ip', 'unknown'), self._params.get('hostname', 'unknown'))
def get_information(self) -> typing.Any: def get_information(self) -> typing.Any:
# Return something useful? :) # Return something useful? :)

View File

@ -51,10 +51,10 @@ class UDSActorSvc(daemon.Daemon, CommonService):
daemon.Daemon.__init__(self, '/var/run/udsactor.pid') daemon.Daemon.__init__(self, '/var/run/udsactor.pid')
CommonService.__init__(self) CommonService.__init__(self)
# Captures signals so we can stop gracefully
signal.signal(signal.SIGINT, self.markForExit) signal.signal(signal.SIGINT, self.markForExit)
signal.signal(signal.SIGTERM, self.markForExit) signal.signal(signal.SIGTERM, self.markForExit)
def markForExit(self, signum, frame) -> None: def markForExit(self, signum, frame) -> None:
self._isAlive = False self._isAlive = False

View File

@ -90,12 +90,12 @@ def writeConfig(config: types.ActorConfigurationType) -> None:
# Ensures exists destination folder # Ensures exists destination folder
dirname = os.path.dirname(CONFIGFILE) dirname = os.path.dirname(CONFIGFILE)
if not os.path.exists(dirname): if not os.path.exists(dirname):
os.mkdir(dirname, mode=0o700) # Will create only if route to path already exists, for example, /etc (that must... :-)) os.mkdir(dirname, mode=0o755) # Will create only if route to path already exists, for example, /etc (that must... :-))
with open(CONFIGFILE, 'w') as f: with open(CONFIGFILE, 'w') as f:
cfg.write(f) cfg.write(f)
os.chmod(CONFIGFILE, 0o0600) # Ensure only readable by root os.chmod(CONFIGFILE, 0o0644) # Ensure only readable by root
def useOldJoinSystem() -> bool: def useOldJoinSystem() -> bool:

View File

@ -58,34 +58,6 @@ class RESTUserServiceNotFoundError(RESTError):
class RESTOsManagerError(RESTError): class RESTOsManagerError(RESTError):
ERRCODE = 4 ERRCODE = 4
# Disable warnings log messages
try:
import urllib3 # @UnusedImport @UnresolvedImport
except Exception:
from requests.packages import urllib3 # @Reimport @UnresolvedImport
try:
urllib3.disable_warnings() # @UndefinedVariable
warnings.simplefilter("ignore")
except Exception:
pass # In fact, isn't too important, but will log warns to logging file
# Constants
def ensureResultIsOk(result: typing.Any) -> None:
if 'error' not in result:
return
for i in (RESTInvalidKeyError, RESTUnmanagedHostError, RESTUserServiceNotFoundError, RESTOsManagerError):
if result['error'] == i.ERRCODE:
raise i(result['result'])
err = RESTError(result['result'])
err.ERRCODE = result['error']
raise err
class REST: class REST:
def __init__(self, host: str, validateCert: bool) -> None: def __init__(self, host: str, validateCert: bool) -> None:
self.host = host self.host = host
@ -93,7 +65,7 @@ class REST:
self.url = "https://{}/uds/rest/".format(self.host) self.url = "https://{}/uds/rest/".format(self.host)
# Disable logging requests messages except for errors, ... # Disable logging requests messages except for errors, ...
logging.getLogger("requests").setLevel(logging.CRITICAL) logging.getLogger("requests").setLevel(logging.CRITICAL)
# Tries to disable all warnings logging.getLogger("urllib3").setLevel(logging.ERROR)
try: try:
warnings.simplefilter("ignore") # Disables all warnings warnings.simplefilter("ignore") # Disables all warnings
except Exception: except Exception:
@ -103,6 +75,24 @@ class REST:
def _headers(self) -> typing.MutableMapping[str, str]: def _headers(self) -> typing.MutableMapping[str, str]:
return {'content-type': 'application/json'} return {'content-type': 'application/json'}
def _actorPost(
self,
method: str, # i.e. 'initialize', 'ready', ....
payLoad: typing.MutableMapping[str, typing.Any],
headers: typing.Optional[typing.MutableMapping[str, str]] = None
) -> typing.Any:
headers = headers or self._headers
try:
result = requests.post(self.url + 'actor/v2/' + method, data=json.dumps(payLoad), headers=headers, verify=self.validateCert)
if result.ok:
return result.json()['result']
except requests.ConnectionError as e:
raise RESTConnectionError(str(e))
except Exception as e:
pass
raise RESTError(result.content)
def _login(self, auth: str, username: str, password: str) -> typing.MutableMapping[str, str]: def _login(self, auth: str, username: str, password: str) -> typing.MutableMapping[str, str]:
try: try:
# First, try to login # First, try to login
@ -120,7 +110,6 @@ class REST:
return headers return headers
def enumerateAuthenticators(self) -> typing.Iterable[types.AuthenticatorType]: def enumerateAuthenticators(self) -> typing.Iterable[types.AuthenticatorType]:
try: try:
result = requests.get(self.url + 'auth/auths', headers=self._headers, verify=self.validateCert, timeout=4) result = requests.get(self.url + 'auth/auths', headers=self._headers, verify=self.validateCert, timeout=4)
@ -137,7 +126,6 @@ class REST:
except Exception: except Exception:
pass pass
def register( #pylint: disable=too-many-arguments, too-many-locals def register( #pylint: disable=too-many-arguments, too-many-locals
self, self,
auth: str, auth: str,
@ -186,36 +174,31 @@ class REST:
'version': VERSION, 'version': VERSION,
'id': [{'mac': i.mac, 'ip': i.ip} for i in interfaces] 'id': [{'mac': i.mac, 'ip': i.ip} for i in interfaces]
} }
try: r = self._actorPost('initialize', payload)
result = requests.post(self.url + 'actor/v2/initialize', data=json.dumps(payload), headers=self._headers, verify=self.validateCert) os = r['os']
if result.ok: return types.InitializationResultType(
r = result.json()['result'] own_token=r['own_token'],
os = r['os'] unique_id=r['unique_id'].lower() if r['unique_id'] else None,
return types.InitializationResultType( max_idle=r['max_idle'],
own_token=r['own_token'], os=types.ActorOsConfigurationType(
unique_id=r['unique_id'].lower() if r['unique_id'] else None, action=os['action'],
max_idle=r['max_idle'], name=os['name'],
os=types.ActorOsConfigurationType( username=os.get('username'),
action=os['action'], password=os.get('password'),
name=os['name'], new_password=os.get('new_password'),
username=os.get('username'), ad=os.get('ad'),
password=os.get('password'), ou=os.get('ou')
new_password=os.get('new_password'), ) if r['os'] else None
ad=os.get('ad'), )
ou=os.get('ou')
) if r['os'] else None
)
except requests.ConnectionError as e:
raise RESTConnectionError(str(e))
except Exception as e:
pass
raise RESTError(result.content) def ready(self, own_token: str, secret: str, ip: str) -> None:
payload = {
def ready(self, own_token: str, secret: str, interfaces: typing.Iterable[types.InterfaceInfoType]) -> None: 'token': own_token,
# TODO: implement ready 'secret': secret,
return 'ip': ip
}
self._actorPost('ready', payload) # Ignores result...
def notifyIpChange(self, own_token: str, secret: str, ip: str) -> None: def notifyIpChange(self, own_token: str, secret: str, ip: str) -> None:
# TODO: implement notifyIpChange # In fact, notifyingIpChange is same as ready right now
return self.ready(own_token, secret, ip)

View File

@ -60,6 +60,8 @@ class CommonService:
_isAlive: bool = True _isAlive: bool = True
_rebootRequested: bool = False _rebootRequested: bool = False
_loggedIn = False _loggedIn = False
_cachedInteface: typing.Optional[types.InterfaceInfoType] = None
_cfg: types.ActorConfigurationType _cfg: types.ActorConfigurationType
_api: rest.REST _api: rest.REST
_interfaces: typing.List[types.InterfaceInfoType] _interfaces: typing.List[types.InterfaceInfoType]
@ -83,6 +85,19 @@ class CommonService:
socket.setdefaulttimeout(20) socket.setdefaulttimeout(20)
def serviceInterfaceInfo(self, interfaces: typing.Optional[typing.List[types.InterfaceInfoType]] = None) -> typing.Optional[types.InterfaceInfoType]:
"""
returns the inteface with unique_id mac or first interface or None if no interfaces...
"""
interfaces = interfaces or self._interfaces
if self._cfg.config and interfaces:
try:
return next(x for x in self._interfaces if x.mac.lower() == self._cfg.config.unique_id)
except StopIteration:
return interfaces[0]
return None
def reboot(self) -> None: def reboot(self) -> None:
self._rebootRequested = True self._rebootRequested = True
@ -94,8 +109,13 @@ class CommonService:
platform.store.writeConfig(self._cfg) platform.store.writeConfig(self._cfg)
if self._cfg.own_token and self._interfaces: if self._cfg.own_token and self._interfaces:
self._api.ready(self._cfg.own_token, self._secret, self._interfaces) srvInterface = self.serviceInterfaceInfo()
# Cleans sensible data if srvInterface:
self._api.ready(self._cfg.own_token, self._secret, srvInterface.ip)
else:
logger.error('Could not locate IP address!!!. (Not registered with UDS)')
# Cleans sensible data
if self._cfg.config: if self._cfg.config:
self._cfg = self._cfg._replace(config=self._cfg.config._replace(os=None), data=None) self._cfg = self._cfg._replace(config=self._cfg.config._replace(os=None), data=None)
platform.store.writeConfig(self._cfg) platform.store.writeConfig(self._cfg)
@ -183,17 +203,10 @@ class CommonService:
# Not enouth data do check # Not enouth data do check
return return
unique_id = self._cfg.config.unique_id
def locateMac(interfaces: typing.Iterable[types.InterfaceInfoType]) -> typing.Optional[types.InterfaceInfoType]:
try:
return next(x for x in interfaces if x.mac.lower() == unique_id)
except StopIteration:
return None
try: try:
old: types.InterfaceInfoType = locateMac(self._interfaces) old = self.serviceInterfaceInfo()
new: types.InterfaceInfoType = locateMac(platform.operations.getNetworkInfo()) new = self.serviceInterfaceInfo(platform.operations.getNetworkInfo())
if not new: if not new or not old:
raise Exception('No ip currently available for {}'.format(self._cfg.config.unique_id)) raise Exception('No ip currently available for {}'.format(self._cfg.config.unique_id))
if old.ip != new.ip: if old.ip != new.ip:
self._api.notifyIpChange(self._cfg.own_token, self._secret, new.ip) self._api.notifyIpChange(self._cfg.own_token, self._secret, new.ip)
@ -265,7 +278,7 @@ class CommonService:
''' '''
logger.info('Service is being stopped') logger.info('Service is being stopped')
def preConnect(self, userName: str, protocol: str) -> str: # pylint: disable=unused-argument def preConnect(self, userName: str, protocol: str, ip: str, hostname: str) -> str: # pylint: disable=unused-argument
''' '''
Invoked when received a PRE Connection request via REST Invoked when received a PRE Connection request via REST
Base preconnect executes the preconnect command Base preconnect executes the preconnect command

View File

@ -147,7 +147,7 @@ class UDSActorSvc(win32serviceutil.ServiceFramework, CommonService):
logger.info('Using multiple step join because configuration requests to do so') logger.info('Using multiple step join because configuration requests to do so')
self.multiStepJoin(name, domain, ou, account, password) self.multiStepJoin(name, domain, ou, account, password)
def preConnect(self, userName: str, protocol: str) -> str: def preConnect(self, userName: str, protocol: str, ip: str, hostname: str) -> str:
logger.debug('Pre connect invoked') logger.debug('Pre connect invoked')
if protocol == 'rdp': # If connection is not using rdp, skip adding user if protocol == 'rdp': # If connection is not using rdp, skip adding user
@ -176,7 +176,7 @@ class UDSActorSvc(win32serviceutil.ServiceFramework, CommonService):
self._user = None self._user = None
logger.debug('User {} already in group'.format(userName)) logger.debug('User {} already in group'.format(userName))
return super().preConnect(userName, protocol) return super().preConnect(userName, protocol, ip, hostname)
def ovLogon(self, username: str, password: str) -> str: def ovLogon(self, username: str, password: str) -> str:
""" """

View File

@ -76,7 +76,7 @@ def writeConfig(config: types.ActorConfigurationType) -> None:
except Exception: except Exception:
key = wreg.CreateKeyEx(BASEKEY, PATH, 0, wreg.KEY_ALL_ACCESS) # @UndefinedVariable key = wreg.CreateKeyEx(BASEKEY, PATH, 0, wreg.KEY_ALL_ACCESS) # @UndefinedVariable
fixRegistryPermissions(key.handle) # fixRegistryPermissions(key.handle)
wreg.SetValueEx(key, "", 0, wreg.REG_BINARY, pickle.dumps(config)) # @UndefinedVariable wreg.SetValueEx(key, "", 0, wreg.REG_BINARY, pickle.dumps(config)) # @UndefinedVariable
wreg.CloseKey(key) # @UndefinedVariable wreg.CloseKey(key) # @UndefinedVariable

View File

@ -41,7 +41,8 @@ from uds.models import (
UserService UserService
) )
from uds.core import VERSION #from uds.core import VERSION
from uds.core.managers import userServiceManager
from uds.core.util.state import State from uds.core.util.state import State
from uds.core.util.cache import Cache from uds.core.util.cache import Cache
from uds.core.util.config import GlobalConfig from uds.core.util.config import GlobalConfig
@ -56,49 +57,65 @@ logger = logging.getLogger(__name__)
ALLOWED_FAILS = 5 ALLOWED_FAILS = 5
def actorResult(result: typing.Any = None, error: typing.Optional[str] = None) -> typing.MutableMapping[str, typing.Any]: class BlockAccess(Exception):
result = result or '' pass
res = {'result': result, 'stamp': getSqlDatetimeAsUnix()}
if error:
res['error'] = error
return res
# Helpers
def checkBlockedIp(ip: str)-> None: def checkBlockedIp(ip: str)-> None:
cache = Cache('actorv2') cache = Cache('actorv2')
fails = cache.get(ip) or 0 fails = cache.get(ip) or 0
if fails > ALLOWED_FAILS: if fails > ALLOWED_FAILS:
logger.info('Access to actor from %s is blocked for %s seconds since last fail', ip, GlobalConfig.LOGIN_BLOCK.getInt()) logger.info('Access to actor from %s is blocked for %s seconds since last fail', ip, GlobalConfig.LOGIN_BLOCK.getInt())
raise Exception() raise BlockAccess()
def incFailedIp(ip: str) -> None: def incFailedIp(ip: str) -> None:
cache = Cache('actorv2') cache = Cache('actorv2')
fails = (cache.get(ip) or 0) + 1 fails = (cache.get(ip) or 0) + 1
cache.put(ip, fails, GlobalConfig.LOGIN_BLOCK.getInt()) cache.put(ip, fails, GlobalConfig.LOGIN_BLOCK.getInt())
# Enclosed methods under /actor path
class ActorV2(Handler):
"""
Processes actor requests
"""
authenticated = False # Actor requests are not authenticated by REST api (except register)
path = 'actor'
name = 'v2'
def get(self):
"""
Processes get requests
"""
logger.debug('Actor args for GET: %s', self._args)
return actorResult({'version': VERSION, 'required': '3.0.0'})
class ActorV2Action(Handler): class ActorV2Action(Handler):
authenticated = False # Actor requests are not authenticated normally authenticated = False # Actor requests are not authenticated normally
path = 'actor/v2' path = 'actor/v2'
def get(self): @staticmethod
return actorResult(VERSION) def actorResult(result: typing.Any = None, error: typing.Optional[str] = None) -> typing.MutableMapping[str, typing.Any]:
result = result or ''
res = {'result': result, 'stamp': getSqlDatetimeAsUnix()}
if error:
res['error'] = error
return res
@staticmethod
def setCommsUrl(userService: UserService, ip: str, secret: str):
url = 'https://{}/actor/{}'.format(userService.getLoggedIP(), secret)
userService.setCommsUrl(url)
def getUserService(self) -> UserService:
'''
Looks for an userService and, if not found, raises a BlockAccess request
'''
try:
return UserService.objects.get(uuid=self._params['token'])
except UserService.DoesNotExist:
raise BlockAccess()
def action(self) -> typing.MutableMapping[str, typing.Any]:
return ActorV2Action.actorResult(error='Base action invoked')
def post(self) -> typing.MutableMapping[str, typing.Any]:
try:
checkBlockedIp(self._request.ip) # pylint: disable=protected-access
result = self.action()
logger.debug('Action result: %s', result)
return result
except BlockAccess:
# For blocking attacks
incFailedIp(self._request.ip) # pylint: disable=protected-access
except Exception:
logger.exception('Posting')
pass
raise AccessDenied('Access denied')
class ActorV2Register(ActorV2Action): class ActorV2Register(ActorV2Action):
""" """
@ -136,7 +153,7 @@ class ActorV2Register(ActorV2Action):
token=secrets.token_urlsafe(36), token=secrets.token_urlsafe(36),
stamp=getSqlDatetime() stamp=getSqlDatetime()
) )
return actorResult(actorToken.token) return ActorV2Action.actorResult(actorToken.token)
class ActorV2Initiialize(ActorV2Action): class ActorV2Initiialize(ActorV2Action):
""" """
@ -145,17 +162,7 @@ class ActorV2Initiialize(ActorV2Action):
""" """
name = 'initialize' name = 'initialize'
def get(self) -> typing.MutableMapping[str, typing.Any]: def action(self) -> typing.MutableMapping[str, typing.Any]:
"""
Processes get requests. Basically checks if this is a "postThoughGet" for OpenGnsys or similar
"""
if self._args[0] == 'PostThoughGet':
self._args = self._args[1:] # Remove first argument
return self.post()
raise RequestError('Invalid request')
def post(self) -> typing.MutableMapping[str, typing.Any]:
""" """
Initialize method expect a json POST with this fields: Initialize method expect a json POST with this fields:
* version: str -> Actor version * version: str -> Actor version
@ -183,7 +190,6 @@ class ActorV2Initiialize(ActorV2Action):
# First, validate token... # First, validate token...
logger.debug('Args: %s, Params: %s', self._args, self._params) logger.debug('Args: %s, Params: %s', self._args, self._params)
try: try:
checkBlockedIp(self._request.ip) # Raises an exception if ip is temporarily blocked
ActorToken.objects.get(token=self._params['token']) # Not assigned, because only needs check ActorToken.objects.get(token=self._params['token']) # Not assigned, because only needs check
# Valid actor token, now validate access allowed. That is, look for a valid mac from the ones provided. # Valid actor token, now validate access allowed. That is, look for a valid mac from the ones provided.
try: try:
@ -195,7 +201,7 @@ class ActorV2Initiialize(ActorV2Action):
) )
except Exception as e: except Exception as e:
logger.info('Unmanaged host request: %s, %s', self._params, e) logger.info('Unmanaged host request: %s, %s', self._params, e)
return actorResult({ return ActorV2Action.actorResult({
'own_token': None, 'own_token': None,
'max_idle': None, 'max_idle': None,
'unique_id': None, 'unique_id': None,
@ -207,44 +213,88 @@ class ActorV2Initiialize(ActorV2Action):
userService.setProperty('actor_version', self._params['version']) userService.setProperty('actor_version', self._params['version'])
maxIdle = None maxIdle = None
osData: typing.MutableMapping[str, typing.Any] = {} osData: typing.MutableMapping[str, typing.Any] = {}
if userService.deployed_service.osmanager: osManager: typing.Optional['osmanagers.OSManager'] = userService.getOsManager()
osManager: 'osmanagers.OSManager' = userService.deployed_service.osmanager.getInstance() if osManager:
maxIdle = osManager.maxIdle() maxIdle = osManager.maxIdle()
logger.debug('Max idle: %s', maxIdle) logger.debug('Max idle: %s', maxIdle)
osData = osManager.actorData(userService) osData = osManager.actorData(userService)
return actorResult({ return ActorV2Action.actorResult({
'own_token': userService.uuid, 'own_token': userService.uuid,
'unique_id': userService.unique_id, 'unique_id': userService.unique_id,
'max_idle': maxIdle, 'max_idle': maxIdle,
'os': osData 'os': osData
}) })
except ActorToken.DoesNotExist: except ActorToken.DoesNotExist:
incFailedIp(self._request.ip) # For blocking attacks raise BlockAccess()
except Exception:
pass
raise AccessDenied('Access denied')
class ActorV2Ready(ActorV2Action):
"""
Notifies the user service is ready
"""
name = 'ready'
def action(self) -> typing.MutableMapping[str, typing.Any]:
"""
Initialize 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
"""
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
ActorV2Action.setCommsUrl(userService, self._params['ip'], self._params['secret'])
if userService.os_state != State.USABLE:
userService.setOsState(State.USABLE)
# Notify osManager or readyness if has os manager
osManager: typing.Optional['osmanagers.OSManager'] = userService.getOsManager()
if osManager:
osManager.toReady(userService)
userServiceManager().notifyReadyFromOsManager(userService, '')
return ActorV2Action.actorResult('ok')
class ActorV2Login(ActorV2Action): class ActorV2Login(ActorV2Action):
""" """
Notifies user logged out Notifies user logged id
""" """
name = 'login' name = 'login'
def post(self): def action(self) -> typing.MutableMapping[str, typing.Any]:
logger.debug('Args: %s, Params: %s', self._args, self._params) logger.debug('Args: %s, Params: %s', self._args, self._params)
return actorResult('ok') userService = self.getUserService()
osManager: typing.Optional['osmanagers.OSManager'] = userService.getOsManager()
if osManager:
osManager.loggedIn(userService, self._params.get('username') or '')
ip, hostname = userService.getConnectionSource()
deadLine = userService.deployed_service.getDeadline()
return ActorV2Action.actorResult({
'ip': ip,
'hostname': hostname,
'dead_line': deadLine
})
class ActorV2Logout(ActorV2Action): class ActorV2Logout(ActorV2Action):
""" """
Notifies user logged in Notifies user logged out
""" """
name = 'logout' name = 'logout'
def post(self): def action(self) -> typing.MutableMapping[str, typing.Any]:
logger.debug('Args: %s, Params: %s', self._args, self._params) logger.debug('Args: %s, Params: %s', self._args, self._params)
return actorResult('ok') return ActorV2Action.actorResult('ok')
class ActorV2Log(ActorV2Action): class ActorV2Log(ActorV2Action):
""" """
@ -252,36 +302,9 @@ class ActorV2Log(ActorV2Action):
""" """
name = 'log' name = 'log'
def post(self): def action(self) -> typing.MutableMapping[str, typing.Any]:
logger.debug('Args: %s, Params: %s', self._args, self._params) logger.debug('Args: %s, Params: %s', self._args, self._params)
return actorResult('ok') return ActorV2Action.actorResult('ok')
class ActorV2Ready(ActorV2Action):
"""
Notifies the service is ready
"""
name = 'ready'
def setCommsUrl(self, userService: UserService, secret: str):
url = 'https://{}/actor/{}'.format(userService.getLoggedIP(), secret)
userService.setCommsUrl(url)
def post(self):
logger.debug('Args: %s, Params: %s', self._args, self._params)
return actorResult('ok')
class ActorV2IpChange(ActorV2Action):
"""
Notifies an IP change
"""
name = 'ipchange'
def post(self):
"""
Records the ip change, and also fix notifyComms url
"""
logger.debug('Args: %s, Params: %s', self._args, self._params)
return actorResult('ok')
class ActorV2Ticket(ActorV2Action): class ActorV2Ticket(ActorV2Action):
""" """
@ -289,6 +312,29 @@ class ActorV2Ticket(ActorV2Action):
""" """
name = 'ticket' name = 'ticket'
def post(self): def action(self) -> typing.MutableMapping[str, typing.Any]:
logger.debug('Args: %s, Params: %s', self._args, self._params) logger.debug('Args: %s, Params: %s', self._args, self._params)
return actorResult('ok') return ActorV2Action.actorResult('ok')
class ActorV2Notify(ActorV2Action):
name = 'notify'
def post(self) -> typing.MutableMapping[str, typing.Any]:
raise AccessDenied('Access denied')
def get(self) -> typing.MutableMapping[str, typing.Any]:
logger.debug('Args: %s, Params: %s', self._args, self._params)
if 'action' not in self._params or 'token' not in self._params or self._params['action'] not in ('login', 'logout'):
# Requested login or logout
raise RequestError('Invalid parameters')
try:
checkBlockedIp(self._request.ip) # pylint: disable=protected-access
userService = UserService.objects.get(uuid=self._params['token'])
# TODO: finish this
return ActorV2Action.actorResult('ok')
except UserService.DoesNotExist:
# For blocking attacks
incFailedIp(self._request.ip) # pylint: disable=protected-access
raise AccessDenied('Access denied')

View File

@ -455,6 +455,8 @@ class UserServiceManager:
''' '''
proxy = userService.deployed_service.proxy proxy = userService.deployed_service.proxy
url = userService.getCommsUrl() url = userService.getCommsUrl()
ip, hostname = userService.getConnectionSource()
if not url: if not url:
logger.debug('No notification is made because agent does not supports notifications') logger.debug('No notification is made because agent does not supports notifications')
return return
@ -462,7 +464,7 @@ class UserServiceManager:
url += '/preConnect' url += '/preConnect'
try: try:
data = {'user': userName, 'protocol': protocol} data = {'user': userName, 'protocol': protocol, 'ip': ip, 'hostname': hostname}
if proxy is not None: if proxy is not None:
r = proxy.doProxyRequest(url=url, data=data, timeout=2) r = proxy.doProxyRequest(url=url, data=data, timeout=2)
else: else:

View File

@ -259,7 +259,7 @@ class UserService(UUIDModel): # pylint: disable=too-many-public-methods
return (self.src_ip, self.src_hostname) return (self.src_ip, self.src_hostname)
def getOsManager(self) -> typing.Optional['OSManager']: def getOsManager(self) -> typing.Optional['OSManager']:
return self.deployed_service.osmanager return self.deployed_service.osmanager.getInstance()
def needsOsManager(self) -> bool: def needsOsManager(self) -> bool:
""" """

View File

@ -71,7 +71,7 @@ class WinDomainOsManager(WindowsOsManager):
grp = gui.TextField(length=64, label=_('Machine Group'), order=7, tooltip=_('Group to which add machines on creation. If empty, no group will be used. (experimental)'), tab=_('Advanced')) grp = gui.TextField(length=64, label=_('Machine Group'), order=7, tooltip=_('Group to which add machines on creation. If empty, no group will be used. (experimental)'), tab=_('Advanced'))
removeOnExit = gui.CheckBoxField(label=_('Machine clean'), order=8, tooltip=_('If checked, UDS will try to remove the machine from the domain USING the provided credentials'), tab=_('Advanced'), defvalue=gui.TRUE) removeOnExit = gui.CheckBoxField(label=_('Machine clean'), order=8, tooltip=_('If checked, UDS will try to remove the machine from the domain USING the provided credentials'), tab=_('Advanced'), defvalue=gui.TRUE)
serverHint = gui.TextField(length=64, label=_('Server Hint'), order=9, tooltip=_('In case of several AD servers, which one is preferred'), tab=_('Advanced')) serverHint = gui.TextField(length=64, label=_('Server Hint'), order=9, tooltip=_('In case of several AD servers, which one is preferred'), tab=_('Advanced'))
ssl = gui.CheckBoxField(label=_('Use SSL'), order=10, tooltip=_('If checked, a ssl connection to Active Directory will be used'), tab=_('Advanced')) ssl = gui.CheckBoxField(label=_('Use SSL'), order=10, tooltip=_('If checked, a ssl connection to Active Directory will be used'), tab=_('Advanced'), defvalue=gui.TRUE)
# Inherits base "onLogout" # Inherits base "onLogout"
onLogout = WindowsOsManager.onLogout onLogout = WindowsOsManager.onLogout