mirror of
https://github.com/dkmstr/openuds.git
synced 2025-01-03 01:17:56 +03:00
Almost finished connector
This commit is contained in:
commit
199e0d3559
1
client/.gitignore
vendored
1
client/.gitignore
vendored
@ -1,3 +1,4 @@
|
|||||||
/bin
|
/bin
|
||||||
/udsclient_*
|
/udsclient_*
|
||||||
|
/udsclient-*.tar.gz
|
||||||
/*.rpm
|
/*.rpm
|
||||||
|
2
client/linux/.gitignore
vendored
2
client/linux/.gitignore
vendored
@ -1,4 +1,4 @@
|
|||||||
/udsclient-opensuse-1.*.spec
|
/udsclient-opensuse-1.*.spec
|
||||||
/udsclient-1.*.spec
|
/udsclient-1.*.spec
|
||||||
/debian/udsclient
|
/debian/udsclient
|
||||||
|
/targz
|
||||||
|
@ -1,6 +1,9 @@
|
|||||||
#!/usr/bin/make -f
|
#!/usr/bin/make -f
|
||||||
# -*- makefile -*-
|
# -*- makefile -*-
|
||||||
|
|
||||||
|
# Version
|
||||||
|
VERSION := 1.7.5
|
||||||
|
|
||||||
# Directories
|
# Directories
|
||||||
SOURCEDIR := ../src
|
SOURCEDIR := ../src
|
||||||
LIBDIR := $(DESTDIR)/usr/lib/UDSClient
|
LIBDIR := $(DESTDIR)/usr/lib/UDSClient
|
||||||
@ -16,8 +19,8 @@ clean:
|
|||||||
install:
|
install:
|
||||||
rm -rf $(DESTDIR)
|
rm -rf $(DESTDIR)
|
||||||
mkdir -p $(LIBDIR)
|
mkdir -p $(LIBDIR)
|
||||||
mkdir -p $(BINDIR)
|
#mkdir -p $(BINDIR)
|
||||||
mkdir -p $(SBINDIR)
|
#mkdir -p $(SBINDIR)
|
||||||
mkdir -p $(APPSDIR)
|
mkdir -p $(APPSDIR)
|
||||||
|
|
||||||
mkdir $(LIBDIR)/uds
|
mkdir $(LIBDIR)/uds
|
||||||
@ -34,9 +37,15 @@ install:
|
|||||||
cp desktop/UDSClient.desktop $(APPSDIR)
|
cp desktop/UDSClient.desktop $(APPSDIR)
|
||||||
|
|
||||||
chmod 755 $(LIBDIR)/UDSClient.py
|
chmod 755 $(LIBDIR)/UDSClient.py
|
||||||
|
|
||||||
|
ifeq ($(DISTRO),targz)
|
||||||
|
cp installer.sh $(DESTDIR)/install.sh
|
||||||
|
tar czvf ../udsclient-$(VERSION).tar.gz -C $(DESTDIR) .
|
||||||
|
endif
|
||||||
|
|
||||||
|
|
||||||
# chmod 0755 $(BINDIR)/udsclient
|
# chmod 0755 $(BINDIR)/udsclient
|
||||||
uninstall:
|
uninstall:
|
||||||
rm -rf $(LIBDIR)
|
rm -rf $(LIBDIR)
|
||||||
# rm -f $(BINDIR)/udsclient
|
# rm -f $(BINDIR)/udsclient
|
||||||
rm -rf $(CFGDIR)
|
# rm -rf $(CFGDIR)
|
||||||
|
@ -2,7 +2,10 @@
|
|||||||
|
|
||||||
VERSION=1.7.5
|
VERSION=1.7.5
|
||||||
RELEASE=1
|
RELEASE=1
|
||||||
|
# Debian based
|
||||||
|
dpkg-buildpackage -b
|
||||||
|
|
||||||
|
# Now rpm based
|
||||||
top=`pwd`
|
top=`pwd`
|
||||||
|
|
||||||
cat udsclient-template.spec |
|
cat udsclient-template.spec |
|
14
client/linux/installer.sh
Normal file
14
client/linux/installer.sh
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
cp -r usr/lib/UDSClient /usr/lib/UDSClient
|
||||||
|
cp -r usr/share/applications /usr/lib/applications -R
|
||||||
|
update-desktop-database
|
||||||
|
|
||||||
|
echo "Installation process done."
|
||||||
|
echo "Remembar that the following packages must be installed on system:"
|
||||||
|
echo "* Python paramiko"
|
||||||
|
echo "* Python pyqt4"
|
||||||
|
echo "Theese packages (as their names), are dependent on your platform, so you must locate and install them"
|
||||||
|
echo "You can install them directly on any platform with pip, using this simple command: "
|
||||||
|
echo "pip install PyQt4 paramiko"
|
||||||
|
|
@ -12,7 +12,7 @@ import threading
|
|||||||
import random
|
import random
|
||||||
import time
|
import time
|
||||||
|
|
||||||
g_verbose = False
|
g_verbose = True
|
||||||
|
|
||||||
|
|
||||||
class ForwardServer (SocketServer.ThreadingTCPServer):
|
class ForwardServer (SocketServer.ThreadingTCPServer):
|
||||||
@ -117,8 +117,9 @@ class ForwardThread(threading.Thread):
|
|||||||
verbose('Connecting to ssh host %s:%d ...' % (self.server, self.port))
|
verbose('Connecting to ssh host %s:%d ...' % (self.server, self.port))
|
||||||
|
|
||||||
try:
|
try:
|
||||||
self.client.connect(self.server, self.port, username=self.username, password=self.password)
|
self.client.connect(self.server, self.port, username=self.username, password=self.password, timeout=5, banner_timeout=10)
|
||||||
except Exception:
|
except Exception as e:
|
||||||
|
verbose('Exception connecting: {}'.format(e))
|
||||||
self.status = 2 # Error
|
self.status = 2 # Error
|
||||||
return
|
return
|
||||||
|
|
||||||
@ -173,3 +174,4 @@ def forward(server, port, username, password, redirectHost, redirectPort, localP
|
|||||||
time.sleep(0.1)
|
time.sleep(0.1)
|
||||||
|
|
||||||
return (ft, localPort)
|
return (ft, localPort)
|
||||||
|
|
||||||
|
@ -70,6 +70,5 @@ class Cache(Handler):
|
|||||||
if len(self._args) != 1:
|
if len(self._args) != 1:
|
||||||
raise RequestError('Invalid Request')
|
raise RequestError('Invalid Request')
|
||||||
|
|
||||||
|
|
||||||
uCache.purge()
|
uCache.purge()
|
||||||
return 'done'
|
return 'done'
|
||||||
|
210
server/src/uds/REST/methods/connection.py
Normal file
210
server/src/uds/REST/methods/connection.py
Normal file
@ -0,0 +1,210 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
#
|
||||||
|
# Copyright (c) 2015 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 __future__ import unicode_literals
|
||||||
|
|
||||||
|
from django.utils.translation import ugettext as _
|
||||||
|
|
||||||
|
from uds.REST import Handler
|
||||||
|
from uds.REST import RequestError
|
||||||
|
from uds.models import UserService, DeployedService, Transport
|
||||||
|
from uds.core.managers.UserServiceManager import UserServiceManager
|
||||||
|
from uds.core.util import log
|
||||||
|
from uds.core.util.stats import events
|
||||||
|
|
||||||
|
|
||||||
|
import datetime
|
||||||
|
import six
|
||||||
|
|
||||||
|
import logging
|
||||||
|
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
# Enclosed methods under /actor path
|
||||||
|
class Connection(Handler):
|
||||||
|
'''
|
||||||
|
Processes actor requests
|
||||||
|
'''
|
||||||
|
authenticated = True # Actor requests are not authenticated
|
||||||
|
needs_admin = False
|
||||||
|
needs_staff = False
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def result(result=None, error=None):
|
||||||
|
'''
|
||||||
|
Helper method to create a "result" set for connection response
|
||||||
|
:param result: Result value to return (can be None, in which case it is converted to empty string '')
|
||||||
|
:param error: If present, This response represents an error. Result will contain an "Explanation" and error contains the error code
|
||||||
|
:return: A dictionary, suitable for response to Caller
|
||||||
|
'''
|
||||||
|
result = result if result is not None else ''
|
||||||
|
res = {'result': result, 'date': datetime.datetime.now()}
|
||||||
|
if error is not None:
|
||||||
|
res['error'] = error
|
||||||
|
return res
|
||||||
|
|
||||||
|
def serviceList(self):
|
||||||
|
# We look for services for this authenticator groups. User is logged in in just 1 authenticator, so his groups must coincide with those assigned to ds
|
||||||
|
groups = list(self._user.getGroups())
|
||||||
|
availServices = DeployedService.getDeployedServicesForGroups(groups)
|
||||||
|
availUserServices = UserService.getUserAssignedServices(self._user)
|
||||||
|
|
||||||
|
# Extract required data to show to user
|
||||||
|
services = []
|
||||||
|
# Select assigned user services
|
||||||
|
for svr in availUserServices:
|
||||||
|
# Skip maintenance services...
|
||||||
|
trans = []
|
||||||
|
for t in svr.transports.all().order_by('priority'):
|
||||||
|
typeTrans = t.getType()
|
||||||
|
if t.validForIp(self._request.ip) and t.getType().providesConnetionInfo():
|
||||||
|
trans.append({'id': t.uuid, 'name': t.name, 'needsJava': t.getType().needsJava})
|
||||||
|
services.append({'id': 'A' + svr.uuid,
|
||||||
|
'name': svr['name'],
|
||||||
|
'transports': trans,
|
||||||
|
'maintenance': svr.deployed_service.service.provider.maintenance_mode,
|
||||||
|
'in_use': svr.in_use})
|
||||||
|
|
||||||
|
logger.debug(services)
|
||||||
|
|
||||||
|
# Now generic user service
|
||||||
|
for svr in availServices:
|
||||||
|
trans = []
|
||||||
|
for t in svr.transports.all().order_by('priority'):
|
||||||
|
if t.validForIp(self._request.ip) and t.getType().providesConnetionInfo():
|
||||||
|
typeTrans = t.getType()
|
||||||
|
trans.append({'id': t.uuid, 'name': t.name, 'needsJava': typeTrans.needsJava})
|
||||||
|
|
||||||
|
# Locate if user service has any already assigned user service for this
|
||||||
|
ads = UserServiceManager.manager().getExistingAssignationForUser(svr, self._user)
|
||||||
|
if ads is None:
|
||||||
|
in_use = False
|
||||||
|
else:
|
||||||
|
in_use = ads.in_use
|
||||||
|
|
||||||
|
services.append({'id': 'F' + svr.uuid,
|
||||||
|
'name': svr.name,
|
||||||
|
'transports': trans,
|
||||||
|
'maintenance': svr.service.provider.maintenance_mode,
|
||||||
|
'in_use': in_use})
|
||||||
|
|
||||||
|
logger.debug('Services: {0}'.format(services))
|
||||||
|
|
||||||
|
services = sorted(services, key=lambda s: s['name'].upper())
|
||||||
|
|
||||||
|
return Connection.result(result=services)
|
||||||
|
|
||||||
|
def connection(self, doNotCheck=False):
|
||||||
|
kind, idService = self._args[0][0], self._args[0][1:]
|
||||||
|
idTransport = self._args[1]
|
||||||
|
|
||||||
|
logger.debug('Type: {}, Service: {}, Transport: {}'.format(kind, idService, idTransport))
|
||||||
|
|
||||||
|
try:
|
||||||
|
logger.debug('Kind of service: {0}, idService: {1}'.format(kind, idService))
|
||||||
|
if kind == 'A': # This is an assigned service
|
||||||
|
ads = UserService.objects.get(uuid=idService)
|
||||||
|
else:
|
||||||
|
ds = DeployedService.objects.get(uuid=idService)
|
||||||
|
# We first do a sanity check for this, if the user has access to this service
|
||||||
|
# If it fails, will raise an exception
|
||||||
|
ds.validateUser(self._user)
|
||||||
|
# Now we have to locate an instance of the service, so we can assign it to user.
|
||||||
|
ads = UserServiceManager.manager().getAssignationForUser(ds, self._user)
|
||||||
|
|
||||||
|
if ads.isInMaintenance() is True:
|
||||||
|
return Connection.result(error='Service in maintenance')
|
||||||
|
|
||||||
|
logger.debug('Found service: {0}'.format(ads))
|
||||||
|
trans = Transport.objects.get(uuid=idTransport)
|
||||||
|
|
||||||
|
if trans.validForIp(self._request.ip) is False:
|
||||||
|
return Connection.result(error='Access denied')
|
||||||
|
|
||||||
|
# Test if the service is ready
|
||||||
|
if doNotCheck or ads.isReady():
|
||||||
|
log.doLog(ads, log.INFO, "User {0} from {1} has initiated access".format(self._user.name, self._request.ip), log.WEB)
|
||||||
|
# If ready, show transport for this service, if also ready ofc
|
||||||
|
iads = ads.getInstance()
|
||||||
|
ip = iads.getIp()
|
||||||
|
logger.debug('IP: {}'.format(ip))
|
||||||
|
events.addEvent(ads.deployed_service, events.ET_ACCESS, username=self._user.name, srcip=self._request.ip, dstip=ip, uniqueid=ads.unique_id)
|
||||||
|
if ip is not None:
|
||||||
|
itrans = trans.getInstance()
|
||||||
|
if itrans.providesConnetionInfo() and (doNotCheck or itrans.isAvailableFor(ip)):
|
||||||
|
ads.setConnectionSource(self._request.ip, 'unknown')
|
||||||
|
log.doLog(ads, log.INFO, "User service ready, rendering transport", log.WEB)
|
||||||
|
|
||||||
|
ci = {
|
||||||
|
'username': '',
|
||||||
|
'password': '',
|
||||||
|
'domain': '',
|
||||||
|
'protocol': 'unknown',
|
||||||
|
'ip': ip
|
||||||
|
}
|
||||||
|
ci.update(itrans.getConnectionInfo(ads, self._user, 'UNKNOWN'))
|
||||||
|
|
||||||
|
UserServiceManager.manager().notifyPreconnect(ads, itrans.processedUser(ads, self._user), itrans.protocol)
|
||||||
|
|
||||||
|
return Connection.result(result=ci)
|
||||||
|
else:
|
||||||
|
log.doLog(ads, log.WARN, "User service is not accessible by REST (ip {0})".format(ip), log.TRANSPORT)
|
||||||
|
logger.debug('Transport {} is not accesible for user service {} from {}'.format(trans, ads, self._request.ip))
|
||||||
|
logger.debug("{}, {}".format(itrans.providesConnetionInfo(), itrans.isAvailableFor(ip)))
|
||||||
|
else:
|
||||||
|
logger.debug('Ip not available from user service {0}'.format(ads))
|
||||||
|
else:
|
||||||
|
log.doLog(ads, log.WARN, "User {0} from {1} tried to access, but service was not ready".format(self._user.name, self._request.ip), log.WEB)
|
||||||
|
# Not ready, show message and return to this page in a while
|
||||||
|
return Connection.result(error='Service not ready')
|
||||||
|
except Exception as e:
|
||||||
|
return Connection.result(error=six.text_type(e))
|
||||||
|
|
||||||
|
def get(self):
|
||||||
|
'''
|
||||||
|
Processes get requests
|
||||||
|
'''
|
||||||
|
logger.debug("Connection args for GET: {0}".format(self._args))
|
||||||
|
|
||||||
|
if len(self._args) == 0:
|
||||||
|
# Return list of services/transports
|
||||||
|
return self.serviceList()
|
||||||
|
|
||||||
|
if len(self._args) == 2:
|
||||||
|
# Return connection & validate access for service/transport
|
||||||
|
return self.connection()
|
||||||
|
|
||||||
|
if len(self._args) == 3 and self._args[2] == 'skipChecking':
|
||||||
|
return self.connection(True)
|
||||||
|
|
||||||
|
raise RequestError('Invalid Request')
|
@ -43,7 +43,7 @@ import threading
|
|||||||
import time
|
import time
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
__updated__ = '2015-02-03'
|
__updated__ = '2015-04-15'
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
@ -185,3 +185,4 @@ class Scheduler(object):
|
|||||||
except Exception, e:
|
except Exception, e:
|
||||||
logger.exception('Unexpected exception at run loop {0}: {1}'.format(e.__class__, e))
|
logger.exception('Unexpected exception at run loop {0}: {1}'.format(e.__class__, e))
|
||||||
logger.info('Exiting Scheduler because stop has been requested')
|
logger.info('Exiting Scheduler because stop has been requested')
|
||||||
|
self.releaseOwnShedules()
|
||||||
|
@ -17,7 +17,7 @@ import six
|
|||||||
forwardThread, port = forward('{m.tunHost}', '{m.tunPort}', '{m.tunUser}', '{m.tunPass}', '{m.ip}', 3389)
|
forwardThread, port = forward('{m.tunHost}', '{m.tunPort}', '{m.tunUser}', '{m.tunPass}', '{m.ip}', 3389)
|
||||||
|
|
||||||
if forwardThread.status == 2:
|
if forwardThread.status == 2:
|
||||||
raise Exception('Unable to open file')
|
raise Exception('Unable to open tunnel')
|
||||||
|
|
||||||
# The password must be encoded, to be included in a .rdp file, as 'UTF-16LE' before protecting (CtrpyProtectData) it in order to work with mstsc
|
# The password must be encoded, to be included in a .rdp file, as 'UTF-16LE' before protecting (CtrpyProtectData) it in order to work with mstsc
|
||||||
theFile = '''{m.r.as_file}'''.format(
|
theFile = '''{m.r.as_file}'''.format(
|
||||||
|
@ -30,7 +30,7 @@
|
|||||||
'''
|
'''
|
||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
__updated__ = '2015-04-01'
|
__updated__ = '2015-04-16'
|
||||||
|
|
||||||
from django.utils.translation import ugettext as _
|
from django.utils.translation import ugettext as _
|
||||||
from django.http import HttpResponse, HttpResponseRedirect
|
from django.http import HttpResponse, HttpResponseRedirect
|
||||||
@ -88,6 +88,10 @@ def getService(request, idService, idTransport, doTest=True):
|
|||||||
if trans not in ads.deployed_service.transports.all():
|
if trans not in ads.deployed_service.transports.all():
|
||||||
raise InvalidServiceException()
|
raise InvalidServiceException()
|
||||||
|
|
||||||
|
# If transport is not available for the request IP...
|
||||||
|
if trans.validForIp(request.ip) is False:
|
||||||
|
raise InvalidServiceException()
|
||||||
|
|
||||||
if doTest is False:
|
if doTest is False:
|
||||||
return (None, ads, None, trans, None)
|
return (None, ads, None, trans, None)
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user