1
0
mirror of https://github.com/dkmstr/openuds.git synced 2025-01-03 01:17:56 +03:00

Included "mac" as a informative field for registered servers

This commit is contained in:
Adolfo Gómez García 2023-07-21 18:27:55 +02:00
parent 7ca11fdb53
commit c0484d628d
No known key found for this signature in database
GPG Key ID: DD1ABF20724CDA23
5 changed files with 49 additions and 34 deletions

View File

@ -86,7 +86,7 @@ class Handler:
_request: 'ExtendedHttpRequestWithUser' # It's a modified HttpRequest
_path: str
_operation: str
_params: typing.Any # This is a deserliazied object from request. Can be anything as 'a' or {'a': 1} or ....
_params: typing.MutableMapping[str, typing.Any] # This is a deserliazied object from request. Can be anything as 'a' or {'a': 1} or ....
_args: typing.Tuple[
str, ...
] # This are the "path" split by /, that is, the REST invocation arguments

View File

@ -276,20 +276,18 @@ class Register(ActorV3Action):
name = 'register'
def post(self) -> typing.MutableMapping[str, typing.Any]:
actorToken: RegisteredServers
# If already exists a token for this MAC, return it instead of creating a new one, and update the information...
# 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
for actorToken in RegisteredServers.objects.filter(kind=RegisteredServers.ServerType.ACTOR):
if actorToken.data and actorToken.data.get('mac', '') == self._params['mac']:
actorToken: typing.Optional[RegisteredServers] = RegisteredServers.objects.filter(kind=RegisteredServers.ServerType.ACTOR, 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.data = { # type: ignore
'mac': self._params['mac'],
'pre_command': self._params['pre_command'],
'post_command': self._params['post_command'],
'run_once_command': self._params['run_once_command'],
@ -300,7 +298,6 @@ class Register(ActorV3Action):
actorToken.save()
logger.info('Registered actor %s', self._params)
found = True
break
if not found:
kwargs = {
@ -310,16 +307,16 @@ class Register(ActorV3Action):
'ip_version': self._request.ip_version,
'hostname': self._params['hostname'],
'data': { # type: ignore
'mac': self._params['mac'],
'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': secrets.token_urlsafe(36),
'token': RegisteredServers.create_token(),
'kind': RegisteredServers.ServerType.ACTOR,
'os_type': self._params.get('os', KnownOS.UNKNOWN.os_name()),
'mac': self._params['mac'],
'stamp': getSqlDatetime(),
}

View File

@ -55,7 +55,9 @@ class ServerRegister(Handler):
serverToken: models.RegisteredServers
now = getSqlDatetimeAsUnix()
try:
# If already exists a token for this MAC, return it instead of creating a new one, and update the information...
# If already exists a token for this, return it instead of creating a new one, and update the information...
# Note that we use IP and HOSTNAME 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=self._params['ip'], hostname=self._params['hostname']
)
@ -72,10 +74,11 @@ class ServerRegister(Handler):
ip_from=self._request.ip,
ip=self._params['ip'],
hostname=self._params['hostname'],
token=secrets.token_urlsafe(36),
token=models.RegisteredServers.create_token(),
stamp=getSqlDatetime(),
kind=self._params['type'],
os_type=typing.cast(str, self._params.get('os', KnownOS.UNKNOWN.os_name())).lower(),
mac=self._params.get('mac', models.RegisteredServers.MAC_UNKNOWN),
data=self._params.get('data', None),
)
except Exception as e:

View File

@ -41,7 +41,7 @@ from uds.core.auths.auth import isTrustedSource
from uds.core.util import log, net
from uds.core.util.stats import events
from .servers import ServerRegister
from .registered_servers import ServerRegister
logger = logging.getLogger(__name__)
@ -162,5 +162,5 @@ 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['os'] = KnownOS.LINUX.os_name() # Legacy tunnels are always linux
self._params['os'] = self._params.get('os', KnownOS.LINUX.os_name()) # Legacy tunnels are always linux
return super().post()

View File

@ -30,6 +30,8 @@ Author: Adolfo Gómez, dkmaster at dkmon dot com
'''
import typing
import enum
import secrets
from uds.core.util.os_detector import KnownOS
from django.db import models
@ -37,6 +39,7 @@ from uds.core.util.request import ExtendedHttpRequest
from .consts import MAX_DNS_NAME_LENGTH, MAX_IPV6_LENGTH
class RegisteredServers(models.Model):
"""
UDS Registered Servers
@ -54,14 +57,18 @@ class RegisteredServers(models.Model):
If server is Other, but not Tunnel, it will be allowed to access API, but will not be able to
create tunnels.
"""
class ServerType(enum.IntFlag):
class ServerType(enum.IntEnum):
TUNNEL = 1
ACTOR = 2
APP_SERVER = 3
OTHER = 99
def as_str(self) -> str:
return self.name.lower() # type: ignore
MAC_UNKNOWN = '00:00:00:00:00:00'
username = models.CharField(max_length=128)
ip_from = models.CharField(max_length=MAX_IPV6_LENGTH)
ip = models.CharField(max_length=MAX_IPV6_LENGTH)
@ -72,18 +79,26 @@ class RegisteredServers(models.Model):
token = models.CharField(max_length=48, db_index=True, unique=True)
stamp = models.DateTimeField() # Date creation or validation of this entry
kind = models.IntegerField(default=ServerType.TUNNEL.value) # Defaults to tunnel server, so we can migrate from previous versions
os_type = models.CharField(max_length=32, default=KnownOS.UNKNOWN.os_name()) # os type of server (linux, windows, etc..)
# Type of server. Defaults to tunnel, so we can migrate from previous versions
kind = models.IntegerField(default=ServerType.TUNNEL.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 actor servers mainly, informative for others
mac = models.CharField(max_length=32, default=MAC_UNKNOWN, db_index=True)
# Extra data, for custom server type use (i.e. actor keeps command related data here)
data = models.JSONField(null=True, blank=True, default=None)
class Meta: # pylint: disable=too-few-public-methods
app_label = 'uds'
@staticmethod
def validateToken(
token: str, request: typing.Optional[ExtendedHttpRequest] = None
) -> bool:
def create_token() -> str:
return secrets.token_urlsafe(36)
@staticmethod
def validateToken(token: str, request: typing.Optional[ExtendedHttpRequest] = None) -> bool:
# Ensure tiken is composed of
try:
tt = RegisteredServers.objects.get(token=token)
# We could check the request ip here