forked from shaba/openuds
advancing on new v3 actor
This commit is contained in:
parent
a8b94325e5
commit
ced7226f81
@ -72,7 +72,7 @@ class PublicProvider(handler.Handler):
|
||||
logger.debug('Received Pre connection')
|
||||
if 'user' not in self._params or 'protocol' not in self._params:
|
||||
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:
|
||||
# Return something useful? :)
|
||||
|
@ -51,10 +51,10 @@ class UDSActorSvc(daemon.Daemon, CommonService):
|
||||
daemon.Daemon.__init__(self, '/var/run/udsactor.pid')
|
||||
CommonService.__init__(self)
|
||||
|
||||
# Captures signals so we can stop gracefully
|
||||
signal.signal(signal.SIGINT, self.markForExit)
|
||||
signal.signal(signal.SIGTERM, self.markForExit)
|
||||
|
||||
|
||||
def markForExit(self, signum, frame) -> None:
|
||||
self._isAlive = False
|
||||
|
||||
|
@ -90,12 +90,12 @@ def writeConfig(config: types.ActorConfigurationType) -> None:
|
||||
# Ensures exists destination folder
|
||||
dirname = os.path.dirname(CONFIGFILE)
|
||||
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:
|
||||
cfg.write(f)
|
||||
|
||||
os.chmod(CONFIGFILE, 0o0600) # Ensure only readable by root
|
||||
os.chmod(CONFIGFILE, 0o0644) # Ensure only readable by root
|
||||
|
||||
|
||||
def useOldJoinSystem() -> bool:
|
||||
|
@ -58,34 +58,6 @@ class RESTUserServiceNotFoundError(RESTError):
|
||||
class RESTOsManagerError(RESTError):
|
||||
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:
|
||||
def __init__(self, host: str, validateCert: bool) -> None:
|
||||
self.host = host
|
||||
@ -93,7 +65,7 @@ class REST:
|
||||
self.url = "https://{}/uds/rest/".format(self.host)
|
||||
# Disable logging requests messages except for errors, ...
|
||||
logging.getLogger("requests").setLevel(logging.CRITICAL)
|
||||
# Tries to disable all warnings
|
||||
logging.getLogger("urllib3").setLevel(logging.ERROR)
|
||||
try:
|
||||
warnings.simplefilter("ignore") # Disables all warnings
|
||||
except Exception:
|
||||
@ -103,6 +75,24 @@ class REST:
|
||||
def _headers(self) -> typing.MutableMapping[str, str]:
|
||||
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]:
|
||||
try:
|
||||
# First, try to login
|
||||
@ -120,7 +110,6 @@ class REST:
|
||||
|
||||
return headers
|
||||
|
||||
|
||||
def enumerateAuthenticators(self) -> typing.Iterable[types.AuthenticatorType]:
|
||||
try:
|
||||
result = requests.get(self.url + 'auth/auths', headers=self._headers, verify=self.validateCert, timeout=4)
|
||||
@ -137,7 +126,6 @@ class REST:
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
|
||||
def register( #pylint: disable=too-many-arguments, too-many-locals
|
||||
self,
|
||||
auth: str,
|
||||
@ -186,36 +174,31 @@ class REST:
|
||||
'version': VERSION,
|
||||
'id': [{'mac': i.mac, 'ip': i.ip} for i in interfaces]
|
||||
}
|
||||
try:
|
||||
result = requests.post(self.url + 'actor/v2/initialize', data=json.dumps(payload), headers=self._headers, verify=self.validateCert)
|
||||
if result.ok:
|
||||
r = result.json()['result']
|
||||
os = r['os']
|
||||
return types.InitializationResultType(
|
||||
own_token=r['own_token'],
|
||||
unique_id=r['unique_id'].lower() if r['unique_id'] else None,
|
||||
max_idle=r['max_idle'],
|
||||
os=types.ActorOsConfigurationType(
|
||||
action=os['action'],
|
||||
name=os['name'],
|
||||
username=os.get('username'),
|
||||
password=os.get('password'),
|
||||
new_password=os.get('new_password'),
|
||||
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
|
||||
r = self._actorPost('initialize', payload)
|
||||
os = r['os']
|
||||
return types.InitializationResultType(
|
||||
own_token=r['own_token'],
|
||||
unique_id=r['unique_id'].lower() if r['unique_id'] else None,
|
||||
max_idle=r['max_idle'],
|
||||
os=types.ActorOsConfigurationType(
|
||||
action=os['action'],
|
||||
name=os['name'],
|
||||
username=os.get('username'),
|
||||
password=os.get('password'),
|
||||
new_password=os.get('new_password'),
|
||||
ad=os.get('ad'),
|
||||
ou=os.get('ou')
|
||||
) if r['os'] else None
|
||||
)
|
||||
|
||||
raise RESTError(result.content)
|
||||
|
||||
def ready(self, own_token: str, secret: str, interfaces: typing.Iterable[types.InterfaceInfoType]) -> None:
|
||||
# TODO: implement ready
|
||||
return
|
||||
def ready(self, own_token: str, secret: str, ip: str) -> None:
|
||||
payload = {
|
||||
'token': own_token,
|
||||
'secret': secret,
|
||||
'ip': ip
|
||||
}
|
||||
self._actorPost('ready', payload) # Ignores result...
|
||||
|
||||
def notifyIpChange(self, own_token: str, secret: str, ip: str) -> None:
|
||||
# TODO: implement notifyIpChange
|
||||
return
|
||||
# In fact, notifyingIpChange is same as ready right now
|
||||
self.ready(own_token, secret, ip)
|
||||
|
@ -60,6 +60,8 @@ class CommonService:
|
||||
_isAlive: bool = True
|
||||
_rebootRequested: bool = False
|
||||
_loggedIn = False
|
||||
_cachedInteface: typing.Optional[types.InterfaceInfoType] = None
|
||||
|
||||
_cfg: types.ActorConfigurationType
|
||||
_api: rest.REST
|
||||
_interfaces: typing.List[types.InterfaceInfoType]
|
||||
@ -83,6 +85,19 @@ class CommonService:
|
||||
|
||||
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:
|
||||
self._rebootRequested = True
|
||||
|
||||
@ -94,8 +109,13 @@ class CommonService:
|
||||
platform.store.writeConfig(self._cfg)
|
||||
|
||||
if self._cfg.own_token and self._interfaces:
|
||||
self._api.ready(self._cfg.own_token, self._secret, self._interfaces)
|
||||
# Cleans sensible data
|
||||
srvInterface = self.serviceInterfaceInfo()
|
||||
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:
|
||||
self._cfg = self._cfg._replace(config=self._cfg.config._replace(os=None), data=None)
|
||||
platform.store.writeConfig(self._cfg)
|
||||
@ -183,17 +203,10 @@ class CommonService:
|
||||
# Not enouth data do check
|
||||
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:
|
||||
old: types.InterfaceInfoType = locateMac(self._interfaces)
|
||||
new: types.InterfaceInfoType = locateMac(platform.operations.getNetworkInfo())
|
||||
if not new:
|
||||
old = self.serviceInterfaceInfo()
|
||||
new = self.serviceInterfaceInfo(platform.operations.getNetworkInfo())
|
||||
if not new or not old:
|
||||
raise Exception('No ip currently available for {}'.format(self._cfg.config.unique_id))
|
||||
if old.ip != 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')
|
||||
|
||||
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
|
||||
Base preconnect executes the preconnect command
|
||||
|
@ -147,7 +147,7 @@ class UDSActorSvc(win32serviceutil.ServiceFramework, CommonService):
|
||||
logger.info('Using multiple step join because configuration requests to do so')
|
||||
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')
|
||||
|
||||
if protocol == 'rdp': # If connection is not using rdp, skip adding user
|
||||
@ -176,7 +176,7 @@ class UDSActorSvc(win32serviceutil.ServiceFramework, CommonService):
|
||||
self._user = None
|
||||
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:
|
||||
"""
|
||||
|
@ -76,7 +76,7 @@ def writeConfig(config: types.ActorConfigurationType) -> None:
|
||||
except Exception:
|
||||
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.CloseKey(key) # @UndefinedVariable
|
||||
|
@ -41,7 +41,8 @@ from uds.models import (
|
||||
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.cache import Cache
|
||||
from uds.core.util.config import GlobalConfig
|
||||
@ -56,49 +57,65 @@ logger = logging.getLogger(__name__)
|
||||
|
||||
ALLOWED_FAILS = 5
|
||||
|
||||
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
|
||||
class BlockAccess(Exception):
|
||||
pass
|
||||
|
||||
# Helpers
|
||||
def checkBlockedIp(ip: str)-> None:
|
||||
cache = Cache('actorv2')
|
||||
fails = cache.get(ip) or 0
|
||||
if fails > ALLOWED_FAILS:
|
||||
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:
|
||||
cache = Cache('actorv2')
|
||||
fails = (cache.get(ip) or 0) + 1
|
||||
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):
|
||||
authenticated = False # Actor requests are not authenticated normally
|
||||
path = 'actor/v2'
|
||||
|
||||
def get(self):
|
||||
return actorResult(VERSION)
|
||||
@staticmethod
|
||||
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):
|
||||
"""
|
||||
@ -136,7 +153,7 @@ class ActorV2Register(ActorV2Action):
|
||||
token=secrets.token_urlsafe(36),
|
||||
stamp=getSqlDatetime()
|
||||
)
|
||||
return actorResult(actorToken.token)
|
||||
return ActorV2Action.actorResult(actorToken.token)
|
||||
|
||||
class ActorV2Initiialize(ActorV2Action):
|
||||
"""
|
||||
@ -145,17 +162,7 @@ class ActorV2Initiialize(ActorV2Action):
|
||||
"""
|
||||
name = 'initialize'
|
||||
|
||||
def get(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]:
|
||||
def action(self) -> typing.MutableMapping[str, typing.Any]:
|
||||
"""
|
||||
Initialize method expect a json POST with this fields:
|
||||
* version: str -> Actor version
|
||||
@ -183,7 +190,6 @@ class ActorV2Initiialize(ActorV2Action):
|
||||
# First, validate token...
|
||||
logger.debug('Args: %s, Params: %s', self._args, self._params)
|
||||
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
|
||||
# Valid actor token, now validate access allowed. That is, look for a valid mac from the ones provided.
|
||||
try:
|
||||
@ -195,7 +201,7 @@ class ActorV2Initiialize(ActorV2Action):
|
||||
)
|
||||
except Exception as e:
|
||||
logger.info('Unmanaged host request: %s, %s', self._params, e)
|
||||
return actorResult({
|
||||
return ActorV2Action.actorResult({
|
||||
'own_token': None,
|
||||
'max_idle': None,
|
||||
'unique_id': None,
|
||||
@ -207,44 +213,88 @@ class ActorV2Initiialize(ActorV2Action):
|
||||
userService.setProperty('actor_version', self._params['version'])
|
||||
maxIdle = None
|
||||
osData: typing.MutableMapping[str, typing.Any] = {}
|
||||
if userService.deployed_service.osmanager:
|
||||
osManager: 'osmanagers.OSManager' = userService.deployed_service.osmanager.getInstance()
|
||||
osManager: typing.Optional['osmanagers.OSManager'] = userService.getOsManager()
|
||||
if osManager:
|
||||
maxIdle = osManager.maxIdle()
|
||||
logger.debug('Max idle: %s', maxIdle)
|
||||
osData = osManager.actorData(userService)
|
||||
|
||||
return actorResult({
|
||||
return ActorV2Action.actorResult({
|
||||
'own_token': userService.uuid,
|
||||
'unique_id': userService.unique_id,
|
||||
'max_idle': maxIdle,
|
||||
'os': osData
|
||||
})
|
||||
except ActorToken.DoesNotExist:
|
||||
incFailedIp(self._request.ip) # For blocking attacks
|
||||
except Exception:
|
||||
pass
|
||||
raise BlockAccess()
|
||||
|
||||
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):
|
||||
"""
|
||||
Notifies user logged out
|
||||
Notifies user logged id
|
||||
"""
|
||||
name = 'login'
|
||||
|
||||
def post(self):
|
||||
def action(self) -> typing.MutableMapping[str, typing.Any]:
|
||||
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):
|
||||
"""
|
||||
Notifies user logged in
|
||||
Notifies user logged out
|
||||
"""
|
||||
name = 'logout'
|
||||
|
||||
def post(self):
|
||||
def action(self) -> typing.MutableMapping[str, typing.Any]:
|
||||
logger.debug('Args: %s, Params: %s', self._args, self._params)
|
||||
return actorResult('ok')
|
||||
return ActorV2Action.actorResult('ok')
|
||||
|
||||
class ActorV2Log(ActorV2Action):
|
||||
"""
|
||||
@ -252,36 +302,9 @@ class ActorV2Log(ActorV2Action):
|
||||
"""
|
||||
name = 'log'
|
||||
|
||||
def post(self):
|
||||
def action(self) -> typing.MutableMapping[str, typing.Any]:
|
||||
logger.debug('Args: %s, Params: %s', self._args, self._params)
|
||||
return 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')
|
||||
return ActorV2Action.actorResult('ok')
|
||||
|
||||
class ActorV2Ticket(ActorV2Action):
|
||||
"""
|
||||
@ -289,6 +312,29 @@ class ActorV2Ticket(ActorV2Action):
|
||||
"""
|
||||
name = 'ticket'
|
||||
|
||||
def post(self):
|
||||
def action(self) -> typing.MutableMapping[str, typing.Any]:
|
||||
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')
|
||||
|
@ -455,6 +455,8 @@ class UserServiceManager:
|
||||
'''
|
||||
proxy = userService.deployed_service.proxy
|
||||
url = userService.getCommsUrl()
|
||||
ip, hostname = userService.getConnectionSource()
|
||||
|
||||
if not url:
|
||||
logger.debug('No notification is made because agent does not supports notifications')
|
||||
return
|
||||
@ -462,7 +464,7 @@ class UserServiceManager:
|
||||
url += '/preConnect'
|
||||
|
||||
try:
|
||||
data = {'user': userName, 'protocol': protocol}
|
||||
data = {'user': userName, 'protocol': protocol, 'ip': ip, 'hostname': hostname}
|
||||
if proxy is not None:
|
||||
r = proxy.doProxyRequest(url=url, data=data, timeout=2)
|
||||
else:
|
||||
|
@ -259,7 +259,7 @@ class UserService(UUIDModel): # pylint: disable=too-many-public-methods
|
||||
return (self.src_ip, self.src_hostname)
|
||||
|
||||
def getOsManager(self) -> typing.Optional['OSManager']:
|
||||
return self.deployed_service.osmanager
|
||||
return self.deployed_service.osmanager.getInstance()
|
||||
|
||||
def needsOsManager(self) -> bool:
|
||||
"""
|
||||
|
@ -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'))
|
||||
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'))
|
||||
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"
|
||||
onLogout = WindowsOsManager.onLogout
|
||||
|
Loading…
x
Reference in New Issue
Block a user