mirror of
https://github.com/dkmstr/openuds.git
synced 2025-01-11 05:17:55 +03:00
Advancing a bit more on server registration, fixing up log level mess
This commit is contained in:
parent
3dc3f4ad56
commit
32c88e1543
2
actor
2
actor
@ -1 +1 @@
|
||||
Subproject commit a0af4f7189ca40f9b42062273d735393b53eb881
|
||||
Subproject commit 6364ac80a36b3606f41eb25c02bede8eaf629f8e
|
@ -48,7 +48,7 @@ logger = logging.getLogger(__name__)
|
||||
|
||||
class ActorTokens(ModelHandler):
|
||||
model = RegisteredServers
|
||||
model_filter = {'kind': RegisteredServers.ServerType.ACTOR}
|
||||
model_filter = {'kind': RegisteredServers.ServerType.ACTOR_SERVICE}
|
||||
|
||||
table_title = _('Actor tokens')
|
||||
table_fields = [
|
||||
@ -65,6 +65,11 @@ class ActorTokens(ModelHandler):
|
||||
|
||||
def item_as_dict(self, item: RegisteredServers) -> typing.Dict[str, typing.Any]:
|
||||
data = item.data or {}
|
||||
log_level_int = data.get('log_level', 2)
|
||||
if log_level_int < 10000: # Old log level
|
||||
log_level = LogLevel.fromActorLevel(log_level_int).name
|
||||
else:
|
||||
log_level = LogLevel(log_level_int).name
|
||||
return {
|
||||
'id': item.token,
|
||||
'name': str(_('Token isued by {} from {}')).format(item.username, item.hostname or item.ip),
|
||||
@ -76,9 +81,7 @@ class ActorTokens(ModelHandler):
|
||||
'pre_command': data.get('pre_command', ''),
|
||||
'post_command': data.get('post_command', ''),
|
||||
'runonce_command': data.get('runonce_command', ''),
|
||||
'log_level': LogLevel.fromActorLevel(
|
||||
data.get('log_level', 2)
|
||||
).name, # ['DEBUG', 'INFO', 'ERROR', 'FATAL'][item.log_level % 4],
|
||||
'log_level': log_level,
|
||||
}
|
||||
|
||||
def delete(self) -> str:
|
||||
|
@ -242,7 +242,7 @@ class Test(ActorV3Action):
|
||||
Service.objects.get(token=self._params['token'])
|
||||
else:
|
||||
RegisteredServers.objects.get(
|
||||
token=self._params['token'], kind=RegisteredServers.ServerType.ACTOR
|
||||
token=self._params['token'], kind=RegisteredServers.ServerType.ACTOR_SERVICE
|
||||
) # Not assigned, because only needs check
|
||||
clearFailedIp(self._request)
|
||||
except Exception:
|
||||
@ -280,18 +280,18 @@ class Register(ActorV3Action):
|
||||
# Look for a token for this mac. mac is "inside" data, so we must filter first by type and then ensure mac is inside data
|
||||
# and mac is the requested one
|
||||
found = False
|
||||
actorToken: typing.Optional[RegisteredServers] = RegisteredServers.objects.filter(kind=RegisteredServers.ServerType.ACTOR, mac=self._params['mac']).first()
|
||||
actorToken: typing.Optional[RegisteredServers] = RegisteredServers.objects.filter(kind=RegisteredServers.ServerType.ACTOR_SERVICE, mac=self._params['mac']).first()
|
||||
if actorToken:
|
||||
# Update parameters
|
||||
actorToken.username = self._user.pretty_name
|
||||
actorToken.ip_from = self._request.ip
|
||||
actorToken.ip = self._params['ip']
|
||||
actorToken.hostname = self._params['hostname']
|
||||
actorToken.log_level = self._params['log_level']
|
||||
actorToken.data = { # type: ignore
|
||||
'pre_command': self._params['pre_command'],
|
||||
'post_command': self._params['post_command'],
|
||||
'run_once_command': self._params['run_once_command'],
|
||||
'log_level': self._params['log_level'],
|
||||
'custom': self._params.get('custom', ''),
|
||||
}
|
||||
actorToken.stamp = getSqlDatetime()
|
||||
@ -306,15 +306,15 @@ class Register(ActorV3Action):
|
||||
'ip': self._params['ip'],
|
||||
'ip_version': self._request.ip_version,
|
||||
'hostname': self._params['hostname'],
|
||||
'log_level': self._params['log_level'],
|
||||
'data': { # type: ignore
|
||||
'pre_command': self._params['pre_command'],
|
||||
'post_command': self._params['post_command'],
|
||||
'run_once_command': self._params['run_once_command'],
|
||||
'log_level': self._params['log_level'],
|
||||
'custom': self._params.get('custom', ''),
|
||||
},
|
||||
'token': RegisteredServers.create_token(),
|
||||
'kind': RegisteredServers.ServerType.ACTOR,
|
||||
'kind': RegisteredServers.ServerType.ACTOR_SERVICE,
|
||||
'os_type': self._params.get('os', KnownOS.UNKNOWN.os_name()),
|
||||
'mac': self._params['mac'],
|
||||
'stamp': getSqlDatetime(),
|
||||
@ -408,9 +408,8 @@ class Initialize(ActorV3Action):
|
||||
dbFilter = UserService.objects.filter(deployed_service__service=service)
|
||||
else:
|
||||
# If not service provided token, use actor tokens
|
||||
RegisteredServers.objects.get(
|
||||
token=token, kind=RegisteredServers.ServerType.ACTOR
|
||||
) # Not assigned, because only needs check
|
||||
if not RegisteredServers.validateToken(token, RegisteredServers.ServerType.ACTOR_SERVICE):
|
||||
raise BlockAccess()
|
||||
# Build the possible ids and make initial filter to match ANY userservice with provided MAC
|
||||
idsList = [i['mac'] for i in self._params['id'][:5]]
|
||||
dbFilter = UserService.objects.all()
|
||||
@ -432,7 +431,7 @@ class Initialize(ActorV3Action):
|
||||
|
||||
# Managed by UDS, get initialization data from osmanager and return it
|
||||
# Set last seen actor version
|
||||
userService.setProperty('actor_version', self._params['version'])
|
||||
userService.setActorVersion(self._params['version'])
|
||||
osData: typing.MutableMapping[str, typing.Any] = {}
|
||||
osManager = userService.getOsManagerInstance()
|
||||
if osManager:
|
||||
@ -444,7 +443,7 @@ class Initialize(ActorV3Action):
|
||||
service.aliases.create(alias=alias_token)
|
||||
|
||||
return initialization_result(userService.uuid, userService.unique_id, osData, alias_token)
|
||||
except (RegisteredServers.DoesNotExist, Service.DoesNotExist):
|
||||
except Service.DoesNotExist:
|
||||
raise BlockAccess() from None
|
||||
|
||||
|
||||
@ -561,7 +560,7 @@ class Version(ActorV3Action):
|
||||
def action(self) -> typing.MutableMapping[str, typing.Any]:
|
||||
logger.debug('Version Args: %s, Params: %s', self._args, self._params)
|
||||
userService = self.getUserService()
|
||||
userService.setProperty('actor_version', self._params['version'])
|
||||
userService.setActorVersion(self._params['version'])
|
||||
userService.logIP(self._params['ip'])
|
||||
|
||||
return ActorV3Action.actorResult()
|
||||
@ -697,13 +696,18 @@ class Log(ActorV3Action):
|
||||
def action(self) -> typing.MutableMapping[str, typing.Any]:
|
||||
logger.debug('Args: %s, Params: %s', self._args, self._params)
|
||||
userService = self.getUserService()
|
||||
# Adjust loglevel to own, we start on 10000 for OTHER, and received is 0 for OTHER
|
||||
if userService.getActorVersion() < '4.0.0':
|
||||
# Adjust loglevel to own, we start on 10000 for OTHER, and received is 0 for OTHER
|
||||
level = log.LogLevel.fromInt(int(self._params['level']) + 10000)
|
||||
else:
|
||||
level = log.LogLevel.fromInt(int(self._params['level']))
|
||||
log.doLog(
|
||||
userService,
|
||||
log.LogLevel.fromInt(int(self._params['level']) + 10000),
|
||||
level,
|
||||
self._params['message'],
|
||||
log.LogSource.ACTOR,
|
||||
)
|
||||
|
||||
|
||||
return ActorV3Action.actorResult('ok')
|
||||
|
||||
@ -720,7 +724,7 @@ class Ticket(ActorV3Action):
|
||||
|
||||
try:
|
||||
# Simple check that token exists
|
||||
RegisteredServers.objects.get(token=self._params['token'], kind=RegisteredServers.ServerType.ACTOR) # Not assigned, because only needs check
|
||||
RegisteredServers.objects.get(token=self._params['token'], kind=RegisteredServers.ServerType.ACTOR_SERVICE) # Not assigned, because only needs check
|
||||
except RegisteredServers.DoesNotExist:
|
||||
raise BlockAccess() from None # If too many blocks...
|
||||
|
||||
|
@ -38,6 +38,7 @@ from django.utils.translation import gettext_lazy as _
|
||||
from uds import models
|
||||
from uds.core.util.model import getSqlDatetimeAsUnix, getSqlDatetime
|
||||
from uds.core.util.os_detector import KnownOS
|
||||
from uds.core.util.log import LogLevel
|
||||
from uds.REST import Handler
|
||||
from uds.REST.exceptions import RequestError, NotFound
|
||||
from uds.REST.model import ModelHandler, OK
|
||||
@ -66,11 +67,12 @@ class ServerRegister(Handler):
|
||||
# Note that we use IP and HOSTNAME (with type) to identify the server, so if any of them changes, a new token will be created
|
||||
# MAC is just informative, and data is used to store any other information that may be needed
|
||||
serverToken = models.RegisteredServers.objects.get(
|
||||
ip=ip, hostname=self._params['hostname'], kind=self._params['type']
|
||||
ip=ip, ip_version=ip_version, hostname=self._params['hostname'], kind=self._params['type']
|
||||
)
|
||||
# Update parameters
|
||||
serverToken.username = self._user.pretty_name
|
||||
serverToken.ip_from = self._request.ip.split('%')[0] # Ensure we do not store zone if IPv6 and present
|
||||
# Ensure we do not store zone if IPv6 and present
|
||||
serverToken.ip_from = self._request.ip.split('%')[0]
|
||||
serverToken.stamp = getSqlDatetime()
|
||||
serverToken.kind = self._params['type']
|
||||
serverToken.save()
|
||||
@ -80,8 +82,10 @@ class ServerRegister(Handler):
|
||||
username=self._user.pretty_name,
|
||||
ip_from=self._request.ip.split('%')[0], # Ensure we do not store zone if IPv6 and present
|
||||
ip=ip,
|
||||
ip_version=ip_version,
|
||||
hostname=self._params['hostname'],
|
||||
token=models.RegisteredServers.create_token(),
|
||||
log_level=self._params.get('log_level', LogLevel.INFO.value),
|
||||
stamp=getSqlDatetime(),
|
||||
kind=self._params['type'],
|
||||
os_type=typing.cast(str, self._params.get('os', KnownOS.UNKNOWN.os_name())).lower(),
|
||||
@ -96,7 +100,7 @@ class ServerRegister(Handler):
|
||||
class ServersTokens(ModelHandler):
|
||||
model = models.RegisteredServers
|
||||
model_filter = {
|
||||
'kind__in': [models.RegisteredServers.ServerType.TUNNEL, models.RegisteredServers.ServerType.OTHER]
|
||||
'kind__in': [models.RegisteredServers.ServerType.TUNNEL_SERVER, models.RegisteredServers.ServerType.OTHER]
|
||||
}
|
||||
path = 'servers'
|
||||
name = 'tokens'
|
||||
|
@ -80,7 +80,7 @@ class TunnelTicket(Handler):
|
||||
|
||||
# Take token from url
|
||||
token = self._args[2][:48]
|
||||
if not models.RegisteredServers.validateToken(token, serverType=models.RegisteredServers.ServerType.TUNNEL):
|
||||
if not models.RegisteredServers.validateToken(token, serverType=models.RegisteredServers.ServerType.TUNNEL_SERVER):
|
||||
if self._args[1][:4] == 'stop':
|
||||
# "Discard" invalid stop requests, because Applications does not like them.
|
||||
# RDS connections keep alive for a while after the application is finished,
|
||||
@ -161,6 +161,6 @@ class TunnelRegister(ServerRegister):
|
||||
|
||||
# Just a compatibility method for old tunnel servers
|
||||
def post(self) -> typing.MutableMapping[str, typing.Any]:
|
||||
self._params['type'] = models.RegisteredServers.ServerType.TUNNEL
|
||||
self._params['type'] = models.RegisteredServers.ServerType.TUNNEL_SERVER
|
||||
self._params['os'] = self._params.get('os', KnownOS.LINUX.os_name()) # Legacy tunnels are always linux
|
||||
return super().post()
|
||||
|
@ -58,7 +58,7 @@ def dict2resp(dct: typing.Mapping[typing.Any, typing.Any]) -> str:
|
||||
|
||||
@auth.trustedSourceRequired
|
||||
def guacamole(request: ExtendedHttpRequestWithUser, token: str, tunnelId: str) -> HttpResponse:
|
||||
if not RegisteredServers.validateToken(token, serverType=RegisteredServers.ServerType.TUNNEL):
|
||||
if not RegisteredServers.validateToken(token, serverType=RegisteredServers.ServerType.TUNNEL_SERVER):
|
||||
logger.error('Invalid token %s from %s', token, request.ip)
|
||||
return HttpResponse(ERROR, content_type=CONTENT_TYPE)
|
||||
logger.debug('Received credentials request for tunnel id %s', tunnelId)
|
||||
|
@ -107,6 +107,11 @@ class Migration(migrations.Migration):
|
||||
name="listen_port",
|
||||
field=models.IntegerField(default=43910),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name="registeredservers",
|
||||
name="log_level",
|
||||
field=models.IntegerField(default=50000),
|
||||
),
|
||||
migrations.RunPython(
|
||||
migrate_old_data,
|
||||
revert_old_data,
|
||||
|
@ -36,6 +36,7 @@ from uds.core.util.os_detector import KnownOS
|
||||
|
||||
from django.db import models
|
||||
from uds.core.util.request import ExtendedHttpRequest
|
||||
from uds.core.util.log import LogLevel
|
||||
|
||||
from .consts import MAX_DNS_NAME_LENGTH, MAX_IPV6_LENGTH
|
||||
|
||||
@ -61,8 +62,8 @@ class RegisteredServers(models.Model):
|
||||
"""
|
||||
|
||||
class ServerType(enum.IntEnum):
|
||||
TUNNEL = 1
|
||||
ACTOR = 2
|
||||
TUNNEL_SERVER = 1
|
||||
ACTOR_SERVICE = 2
|
||||
APP_SERVER = 3
|
||||
OTHER = 99
|
||||
|
||||
@ -71,8 +72,8 @@ class RegisteredServers(models.Model):
|
||||
|
||||
def path(self) -> str:
|
||||
return {
|
||||
RegisteredServers.ServerType.TUNNEL: 'tunnel',
|
||||
RegisteredServers.ServerType.ACTOR: 'actor',
|
||||
RegisteredServers.ServerType.TUNNEL_SERVER: 'tunnel',
|
||||
RegisteredServers.ServerType.ACTOR_SERVICE: 'actor',
|
||||
RegisteredServers.ServerType.APP_SERVER: 'app',
|
||||
RegisteredServers.ServerType.OTHER: 'other',
|
||||
}[self]
|
||||
@ -96,11 +97,13 @@ class RegisteredServers(models.Model):
|
||||
# Note that a server can register itself several times, so we can have several entries
|
||||
# for the same server, but with different types.
|
||||
# (So, for example, an APP_SERVER can be also a TUNNEL_SERVER, because will use both APP API and TUNNEL API)
|
||||
kind = models.IntegerField(default=ServerType.TUNNEL.value)
|
||||
kind = models.IntegerField(default=ServerType.TUNNEL_SERVER.value)
|
||||
# os type of server (linux, windows, etc..)
|
||||
os_type = models.CharField(max_length=32, default=KnownOS.UNKNOWN.os_name())
|
||||
# mac address of registered server, if any. Important for VDI actor servers mainly, informative for others
|
||||
mac = models.CharField(max_length=32, default=MAC_UNKNOWN, db_index=True)
|
||||
# Log level, so we can filter messages for this server
|
||||
log_level = models.IntegerField(default=LogLevel.ERROR.value)
|
||||
|
||||
# Extra data, for custom server type use (i.e. actor keeps command related data here)
|
||||
data = models.JSONField(null=True, blank=True, default=None)
|
||||
|
@ -627,6 +627,12 @@ class UserService(UUIDModel):
|
||||
|
||||
def getLoggedIP(self) -> str:
|
||||
return self.getProperty('ip') or '0.0.0.0' # nosec: no binding address
|
||||
|
||||
def setActorVersion(self, version: typing.Optional[str] = None) -> None:
|
||||
self.setProperty('actor_version', version)
|
||||
|
||||
def getActorVersion(self) -> str:
|
||||
return self.getProperty('actor_version') or '0.0.0'
|
||||
|
||||
def isValidPublication(self) -> bool:
|
||||
"""
|
||||
|
Loading…
Reference in New Issue
Block a user