1
0
mirror of https://github.com/dkmstr/openuds.git synced 2025-01-13 13:17:54 +03:00
This commit is contained in:
Adolfo Gómez García 2017-12-14 15:28:34 +01:00
commit 49862699f2
10 changed files with 90 additions and 92 deletions

@ -69,12 +69,14 @@ install-udsactor:
cp scripts/udsactor $(BINDIR)
cp scripts/UDSActorConfig-pkexec $(SBINDIR)
cp scripts/UDSActorTool-startup $(BINDIR)
cp scripts/udsvapp ${BINDIR}
# Policy to run as administrator
cp policy/org.openuds.pkexec.UDSActorConfig.policy $(POLKITDIR)
# Fix permissions
chmod 755 $(BINDIR)/udsactor
chmod 755 $(BINDIR)/udsvapp
chmod 755 $(BINDIR)/UDSActorTool-startup
chmod 755 $(SBINDIR)/UDSActorConfig-pkexec
chmod 755 $(LIBDIR)/UDSActorConfig.py
@ -93,4 +95,4 @@ endif
uninstall:
rm -rf $(LIBDIR)
# rm -f $(BINDIR)/udsactor
rm -rf $(CFGDIR)
rm -rf $(CFGDIR)

5
actors/linux/scripts/udsvapp Executable file

@ -0,0 +1,5 @@
#!/bin/sh
/usr/bin/udsactor login "$USER"
$@
/usr/bin/udsactor logout "$USER"

@ -60,6 +60,7 @@ This package provides the required components to allow this machine to work on a
/etc/init.d/udsactor
/usr/bin/UDSActorTool-startup
/usr/bin/udsactor
/usr/bin/udsvapp
/usr/bin/UDSActorTool
/usr/sbin/UDSActorConfig
/usr/sbin/UDSActorConfig-pkexec

@ -27,9 +27,11 @@
# 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 __future__ import unicode_literals
import datetime
@ -53,8 +55,6 @@ logger = logging.getLogger(__name__)
# Actor key, configurable in Security Section of administration interface
actorKey = Config.Config.section(Config.SECURITY_SECTION).value('Master Key',
cryptoManager().uuid(datetime.datetime.now()).replace('-', ''),
type=Config.Config.TEXT_FIELD)
actorKey.get()
# Error codes:
@ -70,19 +70,19 @@ SECURE_OWNER = 'SACTOR'
# Enclosed methods under /actor path
class Actor(Handler):
"""
'''
Processes actor requests
"""
'''
authenticated = False # Actor requests are not authenticated
@staticmethod
def result(result=None, error=None):
"""
'''
Helper method to create a "result" set for actor 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:
@ -90,26 +90,26 @@ class Actor(Handler):
return res
def test(self):
"""
'''
Executes and returns the test
"""
'''
return Actor.result(_('Correct'))
def validateRequestKey(self):
"""
'''
Validates a request key (in "key" parameter)
"""
'''
# Ensures that key is first parameter
# Here, path will be .../actor/ACTION/KEY (probably /rest/actor/KEY/...)
logger.debug('{} == {}'.format(self._params.get('key'), actorKey.get(True)))
if self._params.get('key') != actorKey.get(True):
# logger.debug('{} == {}'.format(self._params.get('key'), actorKey.get()))
if self._params.get('key') != actorKey.get():
return Actor.result(_('Invalid key'), error=ERR_INVALID_KEY)
return None
def getUserServiceByIds(self):
"""
'''
This will get the client from the IDs passed from parameters
"""
'''
logger.debug('Getting User services from ids: {}'.format(self._params.get('id')))
try:
@ -124,7 +124,7 @@ class Actor(Handler):
return services[0]
def getTicket(self):
"""
'''
Processes get requests in order to obtain a ticket content
GET /rest/actor/ticket/[ticketId]?key=masterKey&[secure=true|1|false|0]
"""
@ -136,14 +136,14 @@ class Actor(Handler):
raise RequestError('Invalid request')
try:
return Actor.result(TicketStore.get(self._args[1], invalidate=True, owner=SECURE_OWNER if secure else OWNER))
return Actor.result(TicketStore.get(self._args[1], invalidate=True))
except Exception:
return Actor.result({})
def get(self):
"""
'''
Processes get requests
"""
'''
logger.debug("Actor args for GET: {0}".format(self._args))
if len(self._args) < 1:
@ -188,9 +188,9 @@ class Actor(Handler):
# Must be invoked as '/rest/actor/UUID/[message], with message data in post body
def post(self):
"""
'''
Processes post requests
"""
'''
if len(self._args) != 2:
raise RequestError('Invalid request')

@ -27,12 +27,12 @@
# 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, ugettext_lazy as _
from django.utils.translation import ugettext as _
from uds.models import Service, UserService, Tag, Proxy
@ -55,9 +55,9 @@ logger = logging.getLogger(__name__)
class Services(DetailHandler): # pylint: disable=too-many-public-methods
"""
'''
Detail handler for Services, whose parent is a Provider
"""
'''
custom_methods = ['servicesPools']
@ -80,11 +80,11 @@ class Services(DetailHandler): # pylint: disable=too-many-public-methods
@staticmethod
def serviceToDict(item, perm, full=False):
"""
'''
Convert a service db item to a dict for a rest response
:param item: Service item (db)
:param full: If full is requested, add "extra" fields to complete information
"""
'''
itemType = item.getType()
retVal = {
'id': item.uuid,
@ -96,7 +96,7 @@ class Services(DetailHandler): # pylint: disable=too-many-public-methods
'proxy_id': item.proxy.uuid if item.proxy is not None else '-1',
'proxy': item.proxy.name if item.proxy is not None else '',
'deployed_services_count': item.deployedServices.count(),
'user_services_count': UserService.objects.filter(deployed_service__service=item).exclude(state__in=(State.REMOVED, State.ERROR)).count(),
'user_services_count': UserService.objects.filter(deployed_service__service=item).exclude(state__in=State.INFO_STATES).count(),
'maintenance_mode': item.provider.maintenance_mode,
'permission': perm
}
@ -123,10 +123,10 @@ class Services(DetailHandler): # pylint: disable=too-many-public-methods
return {'field': 'maintenance_mode', 'prefix': 'row-maintenance-'}
def _deleteIncompleteService(self, service): # pylint: disable=no-self-use
"""
'''
Deletes a service if it is needed to (that is, if it is not None) and silently catch any exception of this operation
:param service: Service to delete (may be None, in which case it does nothing)
"""
'''
if service is not None:
try:
service.delete()

@ -134,7 +134,7 @@ class ServicesPools(ModelHandler):
'cache_l1_srvs': item.cache_l1_srvs,
'cache_l2_srvs': item.cache_l2_srvs,
'max_srvs': item.max_srvs,
'user_services_count': item.userServices.count(),
'user_services_count': item.userServices.exclude(state__in=State.INFO_STATES).count(),
'user_services_in_preparation': item.userServices.filter(state=State.PREPARING).count(),
'restrained': item.isRestrained(),
'show_transports': item.show_transports,

@ -150,7 +150,6 @@ class Storage(object):
@staticmethod
def delete(owner=None):
logger.info("Deleting storage items")
if owner is None:
objects = dbStorage.objects.all() # @UndefinedVariable
else:

@ -27,9 +27,9 @@
# 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.utils.translation import ugettext_noop as _
from uds.core.managers.UserPrefsManager import CommonPrefs
@ -54,12 +54,11 @@ logger = logging.getLogger(__name__)
READY_CACHE_TIMEOUT = 30
SSH_KEY_LENGTH = 1024
class BaseX2GOTransport(Transport):
"""
'''
Provides access via RDP to service.
This transport can use an domain. If username processed by authenticator contains '@', it will split it and left-@-part will be username, and right password
"""
'''
iconFile = 'x2go.png'
protocol = protocols.X2GO
supportedOss = (OsDetector.Linux, OsDetector.Windows)
@ -78,24 +77,28 @@ class BaseX2GOTransport(Transport):
tab=gui.PARAMETERS_TAB
)
desktopType = gui.ChoiceField(
label=_('Desktop'), order=11, tooltip=_('Desktop session'),
values=[
{'id': 'XFCE', 'text': 'Xfce'},
{'id': 'MATE', 'text': 'Mate'},
{'id': 'LXDE', 'text': 'Lxde'},
{'id': 'GNOME', 'text': 'Gnome (see docs)'},
{'id': 'KDE', 'text': 'Kde (see docs)'},
# {'id': 'UNITY', 'text': 'Unity (see docs)'},
{'id': 'gnome-session-cinnamon', 'text': 'Cinnamon 1.4 (see docs)'},
{'id': 'gnome-session-cinnamon2d', 'text': 'Cinnamon 2.2 (see docs)'},
{'id': '/usr/bin/udsvapp', 'text': 'UDS vAPP'},
],
desktopType = gui.ChoiceField(label=_('Desktop'), order=11, tooltip=_('Desktop session'),
values=[
{'id': 'XFCE', 'text': 'Xfce'},
{'id': 'MATE', 'text': 'Mate'},
{'id': 'LXDE', 'text': 'Lxde'},
{'id': 'GNOME', 'text': 'Gnome (see docs)'},
{'id': 'KDE', 'text': 'Kde (see docs)'},
# {'id': 'UNITY', 'text': 'Unity (see docs)'},
{'id': 'gnome-session-cinnamon', 'text': 'Cinnamon 1.4 (see docs)'},
{'id': 'gnome-session-cinnamon2d', 'text': 'Cinnamon 2.2 (see docs)'},
{'id': 'UDSVAPP', 'text': 'UDS vAPP'},
], tab=gui.PARAMETERS_TAB)
customCmd = gui.TextField(
order=12,
label=_('vAPP'),
tooltip=_('If UDS vAPP is selected as "Desktop", the FULL PATH of the app to be executed. If UDS vAPP is not selected, this field will be ignored.'),
tab=gui.PARAMETERS_TAB
)
sound = gui.CheckBoxField(
order=12,
order=13,
label=_('Enable sound'),
tooltip=_('If checked, sound will be available'),
defvalue=gui.TRUE,
@ -103,7 +106,7 @@ class BaseX2GOTransport(Transport):
)
exports = gui.CheckBoxField(
order=13,
order=14,
label=_('Redirect root folder'),
tooltip=_('If checked, user home folder will be redirected'),
defvalue=gui.FALSE,
@ -112,7 +115,7 @@ class BaseX2GOTransport(Transport):
speed = gui.ChoiceField(
label=_('Speed'),
order=14,
order=15,
tooltip=_('Connection speed'),
defvalue='3',
values=[
@ -121,26 +124,17 @@ class BaseX2GOTransport(Transport):
{'id': '2', 'text': 'ADSL'},
{'id': '3', 'text': 'WAN'},
{'id': '4', 'text': 'LAN'},
],
tab=gui.PARAMETERS_TAB
)
], tab=gui.PARAMETERS_TAB)
soundType = gui.ChoiceField(
label=_('Sound'),
order=30,
tooltip=_('Sound server'),
soundType = gui.ChoiceField(label=_('Sound'), order=30, tooltip=_('Sound server'),
defvalue='pulse',
values=[
{'id': 'pulse', 'text': 'Pulse'},
{'id': 'esd', 'text': 'ESD'},
],
tab=gui.ADVANCED_TAB
], tab=gui.ADVANCED_TAB
)
keyboardLayout = gui.TextField(
label=_('Keyboard'),
order=31,
tooltip=_('Keyboard layout (es, us, fr, ...). Empty value means autodetect.'),
keyboardLayout = gui.TextField(label=_('Keyboard'), order=31, tooltip=_('Keyboard layout (es, us, fr, ...). Empty value means autodetect.'),
defvalue='',
tab=gui.ADVANCED_TAB
)
@ -157,31 +151,20 @@ class BaseX2GOTransport(Transport):
# '8-png-%', '64-png', '256-png', '512-png', '4k-png'
# '32k-png', '64k-png', '256k-png', '2m-png', '16m-png-%'
# '16m-rgb-%', '16m-rle-%'
pack = gui.TextField(
label=_('Pack'),
order=32,
tooltip=_('Pack format. Change with care!'),
pack = gui.TextField(label=_('Pack'), order=32, tooltip=_('Pack format. Change with care!'),
defvalue='16m-jpeg',
tab=gui.ADVANCED_TAB
)
quality = gui.NumericField(
label=_('Quality'),
order=33,
tooltip=_('Quality value used on some pack formats.'),
length=1,
defvalue='6',
minValue=1,
maxValue=9,
required=True,
tab=gui.ADVANCED_TAB
)
quality = gui.NumericField(label=_('Quality'), order=33, tooltip=_('Quality value used on some pack formats.'),
length=1, defvalue='6', minValue=1, maxValue=9, required=True,
tab=gui.ADVANCED_TAB)
def isAvailableFor(self, userService, ip):
"""
'''
Checks if the transport is available for the requested destination ip
Override this in yours transports
"""
'''
logger.debug('Checking availability for {0}'.format(ip))
ready = self.cache.get(ip)
if ready is None:
@ -212,7 +195,7 @@ class BaseX2GOTransport(Transport):
return self.processUserPassword(service, user, password)
def genKeyPairForSsh(self):
"""
'''
Generates a key pair for use with x2go
The private part is used by client
the public part must be "appended" to authorized_keys if it is not already added.
@ -224,14 +207,14 @@ class BaseX2GOTransport(Transport):
C:\Program Files (x86)\\x2goclient>x2goclient.exe --session-conf=c:/temp/sessions --session=UDS/test-session --close-disconnect --hide --no-menu
Linux (tested):
HOME=[temporal folder, where we create a .x2goclient folder and a sessions inside] pyhoca-cli -P UDS/test-session
"""
'''
key = paramiko.RSAKey.generate(SSH_KEY_LENGTH)
privFile = six.StringIO()
key.write_private_key(privFile)
priv = privFile.getvalue()
pub = key.get_base64() # 'ssh-rsa {} UDS@X2GOCLIENT'.format(key.get_base64())
return priv, pub
return (priv, pub)
def getAuthorizeScript(self, user, pubKey):
return self.getScript('scripts/authorize.py').replace('__USER__', user).replace('__KEY__', pubKey)

@ -65,6 +65,7 @@ class TX2GOTransport(BaseX2GOTransport):
fixedName = BaseX2GOTransport.fixedName
# fullScreen = BaseX2GOTransport.fullScreen
desktopType = BaseX2GOTransport.desktopType
customCmd = BaseX2GOTransport.customCmd
sound = BaseX2GOTransport.sound
exports = BaseX2GOTransport.exports
speed = BaseX2GOTransport.speed
@ -89,7 +90,9 @@ class TX2GOTransport(BaseX2GOTransport):
width, height = CommonPrefs.getWidthHeight(prefs)
logger.debug('')
desktop = self.desktopType.value
if desktop == "UDSVAPP":
desktop = "/usr/bin/udsvapp " + self.customCmd.value
xf = x2gofile.getTemplate(
speed=self.speed.value,
@ -97,7 +100,7 @@ class TX2GOTransport(BaseX2GOTransport):
quality=self.quality.value,
sound=self.sound.isTrue(),
soundSystem=self.sound.value,
windowManager=self.desktopType.value,
windowManager=desktop,
exports=self.exports.isTrue(),
width=width,
height=height,

@ -58,6 +58,7 @@ class X2GOTransport(BaseX2GOTransport):
fixedName = BaseX2GOTransport.fixedName
# fullScreen = BaseX2GOTransport.fullScreen
desktopType = BaseX2GOTransport.desktopType
customCmd = BaseX2GOTransport.customCmd
sound = BaseX2GOTransport.sound
exports = BaseX2GOTransport.exports
speed = BaseX2GOTransport.speed
@ -76,13 +77,17 @@ class X2GOTransport(BaseX2GOTransport):
width, height = CommonPrefs.getWidthHeight(prefs)
desktop = self.desktopType.value
if desktop == "UDSVAPP":
desktop = "/usr/bin/udsvapp " + self.customCmd.value
xf = x2gofile.getTemplate(
speed=self.speed.value,
pack=self.pack.value,
quality=self.quality.value,
sound=self.sound.isTrue(),
soundSystem=self.sound.value,
windowManager=self.desktopType.value,
windowManager=desktop,
exports=self.exports.isTrue(),
width=width,
height=height,