forked from shaba/openuds
Improved check of tunneled requests
This commit is contained in:
parent
9a3913cc42
commit
ede23ad793
@ -128,7 +128,6 @@ class TunnelTicket(Handler):
|
|||||||
log.doLog(user.manager, log.INFO, msg)
|
log.doLog(user.manager, log.INFO, msg)
|
||||||
log.doLog(userService, log.INFO, msg)
|
log.doLog(userService, log.INFO, msg)
|
||||||
# Generate new, notify only, ticket
|
# Generate new, notify only, ticket
|
||||||
rstr = managers.cryptoManager().randomString(length=8)
|
|
||||||
notifyTicket = models.TicketStore.create_for_tunnel(
|
notifyTicket = models.TicketStore.create_for_tunnel(
|
||||||
userService=userService,
|
userService=userService,
|
||||||
port=port,
|
port=port,
|
||||||
|
@ -54,13 +54,13 @@ def dict2resp(dct: typing.Mapping[typing.Any, typing.Any]) -> str:
|
|||||||
return '\r'.join((str(k) + '\t' + str(v) for k, v in dct.items()))
|
return '\r'.join((str(k) + '\t' + str(v) for k, v in dct.items()))
|
||||||
|
|
||||||
|
|
||||||
|
@auth.trustedSourceRequired
|
||||||
def guacamole(
|
def guacamole(
|
||||||
request: ExtendedHttpRequestWithUser, token: str, tunnelId: str
|
request: ExtendedHttpRequestWithUser, token: str, tunnelId: str
|
||||||
) -> HttpResponse:
|
) -> HttpResponse:
|
||||||
if not TunnelToken.validateToken(token):
|
if not TunnelToken.validateToken(token):
|
||||||
logger.error('Invalid token %s from %s', token, request.ip)
|
logger.error('Invalid token %s from %s', token, request.ip)
|
||||||
return HttpResponse(ERROR, content_type=CONTENT_TYPE)
|
return HttpResponse(ERROR, content_type=CONTENT_TYPE)
|
||||||
# TODO: Check the authId validity
|
|
||||||
logger.debug('Received credentials request for tunnel id %s', tunnelId)
|
logger.debug('Received credentials request for tunnel id %s', tunnelId)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
@ -73,11 +73,13 @@ def guacamole(
|
|||||||
|
|
||||||
# Extra check that the ticket data belongs to original requested user service/user
|
# Extra check that the ticket data belongs to original requested user service/user
|
||||||
if 'ticket-info' in val:
|
if 'ticket-info' in val:
|
||||||
ti = typing.cast(typing.Mapping[str, str], val['ticket-info'])
|
ti = typing.cast(typing.Mapping[str, str], val['ticket-info']) # recast to dict
|
||||||
del val['ticket-info'] # Do not send this data to guacamole!! :)
|
del val['ticket-info'] # Do not send this data to guacamole!! :)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
userService = UserService.objects.get(uuid=ti['userService'])
|
userService = UserService.objects.get(uuid=ti['userService'])
|
||||||
|
if not userService.isUsable():
|
||||||
|
raise Exception() # Not usable, so we will not use it :)
|
||||||
# Log message and event
|
# Log message and event
|
||||||
protocol = 'RDS' if 'remote-app' in val else val['protocol'].upper()
|
protocol = 'RDS' if 'remote-app' in val else val['protocol'].upper()
|
||||||
host = val.get('hostname', '0.0.0.0')
|
host = val.get('hostname', '0.0.0.0')
|
||||||
@ -99,12 +101,12 @@ def guacamole(
|
|||||||
logger.error(
|
logger.error(
|
||||||
'The requested guacamole userservice does not exists anymore'
|
'The requested guacamole userservice does not exists anymore'
|
||||||
)
|
)
|
||||||
raise
|
raise # Let it be handled by the upper layers
|
||||||
if userService.user.uuid != ti['user']:
|
if userService.user.uuid != ti['user']:
|
||||||
logger.error(
|
logger.error(
|
||||||
'The requested userservice has changed owner and is not accesible'
|
'The requested userservice has changed owner and is not accesible'
|
||||||
)
|
)
|
||||||
raise Exception()
|
raise Exception() # Let it be handled by the upper layers
|
||||||
|
|
||||||
if 'password' in val:
|
if 'password' in val:
|
||||||
val['password'] = cryptoManager().symDecrpyt(val['password'], scrambler)
|
val['password'] = cryptoManager().symDecrpyt(val['password'], scrambler)
|
||||||
|
@ -1,41 +0,0 @@
|
|||||||
# -*- coding: utf-8 -*-
|
|
||||||
|
|
||||||
#
|
|
||||||
# Copyright (c) 2012-2019 Virtual Cable S.L.
|
|
||||||
# All rights reserved.
|
|
||||||
#
|
|
||||||
# Redistribution and use in source and binary forms, with or without modification,
|
|
||||||
# are permitted provided that the following conditions are met:
|
|
||||||
#
|
|
||||||
# * Redistributions of source code must retain the above copyright notice,
|
|
||||||
# this list of conditions and the following disclaimer.
|
|
||||||
# * Redistributions in binary form must reproduce the above copyright notice,
|
|
||||||
# this list of conditions and the following disclaimer in the documentation
|
|
||||||
# and/or other materials provided with the distribution.
|
|
||||||
# * Neither the name of Virtual Cable S.L. nor the names of its contributors
|
|
||||||
# may be used to endorse or promote products derived from this software
|
|
||||||
# without specific prior written permission.
|
|
||||||
#
|
|
||||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
||||||
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
||||||
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
||||||
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
|
||||||
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
||||||
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
|
||||||
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
|
||||||
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
|
||||||
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
||||||
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
|
|
||||||
"""
|
|
||||||
@author: Adolfo Gómez, dkmaster at dkmon dot com
|
|
||||||
"""
|
|
||||||
from django.conf.urls import url
|
|
||||||
from .views import pam
|
|
||||||
|
|
||||||
urlpatterns = [
|
|
||||||
# Old, compat
|
|
||||||
url(r'^pam$', pam, name='dispatcher.pam'),
|
|
||||||
# New
|
|
||||||
url(r'^uds/pam$', pam, name='dispatcher.pam'),
|
|
||||||
]
|
|
@ -1,83 +0,0 @@
|
|||||||
# -*- coding: utf-8 -*-
|
|
||||||
|
|
||||||
#
|
|
||||||
# Copyright (c) 2012-2019 Virtual Cable S.L.
|
|
||||||
# All rights reserved.
|
|
||||||
#
|
|
||||||
# Redistribution and use in source and binary forms, with or without modification,
|
|
||||||
# are permitted provided that the following conditions are met:
|
|
||||||
#
|
|
||||||
# * Redistributions of source code must retain the above copyright notice,
|
|
||||||
# this list of conditions and the following disclaimer.
|
|
||||||
# * Redistributions in binary form must reproduce the above copyright notice,
|
|
||||||
# this list of conditions and the following disclaimer in the documentation
|
|
||||||
# and/or other materials provided with the distribution.
|
|
||||||
# * Neither the name of Virtual Cable S.L. nor the names of its contributors
|
|
||||||
# may be used to endorse or promote products derived from this software
|
|
||||||
# without specific prior written permission.
|
|
||||||
#
|
|
||||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
||||||
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
||||||
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
||||||
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
|
||||||
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
||||||
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
|
||||||
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
|
||||||
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
|
||||||
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
||||||
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
|
|
||||||
"""
|
|
||||||
@author: Adolfo Gómez, dkmaster at dkmon dot com
|
|
||||||
"""
|
|
||||||
import logging
|
|
||||||
|
|
||||||
from django.http import HttpResponseNotAllowed, HttpResponse, HttpRequest
|
|
||||||
from uds.models import TicketStore
|
|
||||||
from uds.core.auths import auth
|
|
||||||
from uds.core.util.request import ExtendedHttpRequestWithUser
|
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
|
||||||
|
|
||||||
# We will use the cache to "hold" the tickets valid for users
|
|
||||||
|
|
||||||
|
|
||||||
@auth.trustedSourceRequired
|
|
||||||
def pam(request: ExtendedHttpRequestWithUser) -> HttpResponse:
|
|
||||||
response = ''
|
|
||||||
if request.method == 'POST':
|
|
||||||
return HttpResponseNotAllowed(['GET'])
|
|
||||||
if 'id' in request.GET and 'pass' in request.GET:
|
|
||||||
# This is an "auth" request
|
|
||||||
ids = request.GET.getlist('id')
|
|
||||||
response = '0'
|
|
||||||
# If request is not forged...
|
|
||||||
if len(ids) == 1:
|
|
||||||
userId = ids[0]
|
|
||||||
logger.debug(
|
|
||||||
"Auth request for user [%s] and pass [%s]",
|
|
||||||
request.GET['id'],
|
|
||||||
request.GET['pass'],
|
|
||||||
)
|
|
||||||
try:
|
|
||||||
password = TicketStore.get(userId)
|
|
||||||
if password == request.GET['pass']:
|
|
||||||
response = '1'
|
|
||||||
except Exception:
|
|
||||||
# Non existing ticket, log it and stop
|
|
||||||
logger.info('Invalid access from %s using user %s', request.ip, userId)
|
|
||||||
else:
|
|
||||||
logger.warning(
|
|
||||||
'Invalid request from %s: %s',
|
|
||||||
request.ip,
|
|
||||||
[v for v in request.GET.lists()],
|
|
||||||
)
|
|
||||||
elif 'uid' in request.GET:
|
|
||||||
# This is an "get name for id" call
|
|
||||||
logger.debug("NSS Request for id [%s]", request.GET['uid'])
|
|
||||||
response = '10000 udstmp'
|
|
||||||
elif 'name' in request.GET:
|
|
||||||
logger.debug("NSS Request for username [%s]", request.GET['name'])
|
|
||||||
response = '10000 udstmp'
|
|
||||||
|
|
||||||
return HttpResponse(response, content_type='text/plain')
|
|
@ -236,6 +236,10 @@ class TicketStore(UUIDModel):
|
|||||||
# if not found any, will raise an execption
|
# if not found any, will raise an execption
|
||||||
user = User.objects.get(uuid=data['u'])
|
user = User.objects.get(uuid=data['u'])
|
||||||
userService = UserService.objects.get(uuid=data['s'], user=user)
|
userService = UserService.objects.get(uuid=data['s'], user=user)
|
||||||
|
# Ensure userservice is usable
|
||||||
|
if not userService.isUsable():
|
||||||
|
raise Exception('Service is not usable') # Not usable, so we will not use it :)
|
||||||
|
|
||||||
host = data['h']
|
host = data['h']
|
||||||
|
|
||||||
if not host:
|
if not host:
|
||||||
|
Loading…
Reference in New Issue
Block a user