mirror of
https://github.com/dkmstr/openuds.git
synced 2025-01-13 13:17:54 +03:00
Merged
This commit is contained in:
commit
49862699f2
actors/linux
server/src/uds
REST/methods
core/util
transports/X2GO
@ -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
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,
|
||||
|
Loading…
x
Reference in New Issue
Block a user