xpra icon
Bug tracker and wiki

This bug tracker and wiki are being discontinued
please use https://github.com/Xpra-org/xpra instead.


Ticket #2125: evolve.patch

File evolve.patch, 15.4 KB (added by brief, 2 years ago)
  • src/xpra/scripts/config.py

     
    634634                    "password-file"     : list,
    635635                    "start-env"         : list,
    636636                    "env"               : list,
     637                    "proxy-sessions"    : list,
     638                    "proxies"           : list,
    637639               }
    638640
    639641#in the options list, available in session files,
     
    740742    "start-after-connect", "start-child-after-connect",
    741743    "start-on-connect", "start-child-on-connect",
    742744    "start-on-last-client-exit", "start-child-on-last-client-exit",
     745    "proxy-sessions",
    743746    ]
    744747tmp = os.environ.get("XPRA_PROXY_START_OVERRIDABLE_OPTIONS", "")
    745748if tmp:
     
    10461049                    "start-child-on-last-client-exit"   : [],
    10471050                    "start-env"         : DEFAULT_ENV,
    10481051                    "env"               : [],
     1052                    "proxy-sessions"    : ["auth"],
     1053                    "proxies"           : [],
    10491054                    }
    10501055    return GLOBAL_DEFAULTS
    10511056#fields that got renamed:
  • src/xpra/scripts/main.py

     
    3434    parse_vsock, parse_env, is_local,
    3535    fixup_defaults, validated_encodings, validate_encryption, do_parse_cmdline, show_sound_codec_help,
    3636    supports_shadow, supports_server, supports_proxy, supports_mdns,
    37     )
     37    validate_proxy_sessions, validate_proxies)
    3838from xpra.scripts.config import (
    3939    OPTION_TYPES, TRUE_OPTIONS, CLIENT_OPTIONS, NON_COMMAND_LINE_OPTIONS, CLIENT_ONLY_OPTIONS,
    4040    START_COMMAND_OPTIONS, BIND_OPTIONS, PROXY_START_OVERRIDABLE_OPTIONS, OPTIONS_ADDED_SINCE_V1, OPTIONS_COMPAT_NAMES,
     
    350350            from xpra.platform import set_name
    351351            set_name("Xpra", "Xpra %s" % mode.strip("_"))
    352352
     353    if mode == "proxy" and options.proxy_sessions:
     354        validate_proxy_sessions(options.proxy_sessions)
     355
     356    if mode in (      # TODO not sure here
     357        "start", "start-desktop", "shadow",
     358        "request-start", "request-start-desktop", "request-shadow",
     359    ) and options.proxies:
     360        validate_proxies(options.proxies)
     361
    353362    if mode in (
    354363        "start", "start-desktop",
    355364        "shadow", "attach", "listen",
  • src/xpra/scripts/parsing.py

     
    11831183                      metavar="FILE",
    11841184                      help="Specifies the file containing the encryption key to use for TCP sockets."
    11851185                      +" (default: '%default')")
     1186    group.add_option("--proxy-sessions", action="append",
     1187                      dest = "proxy_sessions_sources", default=list(defaults.defaults.proxy_sessions_sources or []),
     1188                      help = "Specifies the source of sessions a proxy server offers. Default: %s."%enabled_str(defaults.proxy_sessions_sources))
     1189    group.add_option("--proxies", action="append",
     1190                     dest="proxies", default = list(defaults.register or []),
     1191                     help = "Specifies the proxies to register to.")
    11861192
    11871193    options, args = parser.parse_args(cmdline[1:])
    11881194
     
    13491355    #        raise InitException("tcp-encryption %s should not use the same file"
    13501356    #                            +" as the password authentication file" % tcp_encryption)
    13511357
     1358def validate_proxy_sessions(proxy_sessions):
     1359    for proxy_session in proxy_sessions:
     1360        if not proxy_session in (
     1361            "auth", "sys",
     1362            "mdns", "register",
     1363        ):
     1364            raise InitException("invalid source on proxy-sessions: %s"%proxy_session)
     1365
     1366def validate_proxies(proxies):
     1367    # TODO ?
     1368    return
     1369
    13521370def show_sound_codec_help(is_server, speaker_codecs, microphone_codecs):
    13531371    from xpra.sound.wrapper import query_sound
    13541372    props = query_sound()
  • src/xpra/scripts/server.py

     
    394394    clobber   = int(upgrading or upgrading_desktop)*CLOBBER_UPGRADE | int(use_display)*CLOBBER_USE_DISPLAY
    395395    start_vfb = not (shadowing or proxying or clobber)
    396396
     397    if not proxying and opts.proxy_sessions:
     398        warn("Warning: the 'proxy-sessions' option is used,")
     399        warn("but proxy is not enabled")
     400       
     401    if proxying and opts.proxies:              # TODO not sure what to add here
     402        warn("Warning: the 'proxies' option is used,")
     403        warn("but no server started")          # TODO
     404    elif not proxying and opts.proxies:        # TODO
     405        def register_at_proxies(self):
     406           
     407            # separate thread?
     408       
     409       
     410            for proxy in self.proxies:
     411                # TODO try to register on proxy with token
     412                get_util_logger().debug(proxy)
     413
     414
     415            # TODO exponential back-off
     416            # repeat
     417            add_when_ready(register_at_proxies)
     418            return
     419               
     420        add_when_ready(register_at_proxies)
     421   
    397422    if not proxying and POSIX and not OSX:
    398423        #we don't support wayland servers,
    399424        #so make sure GDK will use the X11 backend:
  • src/xpra/server/auth/sqlauthbase.py

     
    1818                                         "FROM users WHERE username=(%s) AND password=(%s)")
    1919        super().__init__(username, **kwargs)
    2020        self.authenticate = self.authenticate_hmac
     21        self.ALLOWS_REGISTRATION = True
    2122
    2223    def db_cursor(self, *sqlargs):
    2324        raise NotImplementedError()
     
    5859        return uid, gid, displays, env_options, session_options
    5960
    6061
     62    def get_session_by_token(self, token):
     63        pass
     64
     65    def create_session(self, token, name, ip, new_token, display_name):
     66        last_seen = now
     67        # TODO use keep-alive time default from user?
     68        pass
     69
     70    def update_session(self, id, ip):
     71        last_seen = now
     72        pass
     73
     74    def delete_session(self, id):
     75        # TODO periodically?
     76        pass
     77
     78    def get_user(self, userid, password):
     79        # TODO
     80       
     81        pass
     82
     83   
     84
     85
    6186class DatabaseUtilBase:
    6287
    6388    def __init__(self, uri):
  • src/xpra/server/auth/sys_auth_base.py

     
    190190        log("%s.get_sessions()=%s", self, v)
    191191        return v
    192192
     193    # to be overwriten
     194    def get_session_by_token(self, token):
     195        pass
    193196
     197    # to be overwriten
     198    def create_session(self, token, name, ip, new_token, display_name):
     199        last_seen = now
     200        pass
     201
     202    # to be overwriten
     203    def update_session(self, id, ip):
     204        last_seen = now
     205        pass
     206
     207    # to be overwriten
     208    def delete_session(self, id):
     209        # TODO periodically?
     210        pass
     211
     212    # to be overwriten
     213    def get_user(self, userid, password):
     214        # TODO
     215        pass
     216
    194217class SysAuthenticator(SysAuthenticatorBase):
    195218
    196219    def __init__(self, username, **kwargs):
    197220        super().__init__(username)
     221        self.ALLOWS_REGISTRATION = False
    198222        self.pw = None
    199223        if POSIX:
    200224            try:
  • src/xpra/server/proxy/proxy_server.py

     
    1010from multiprocessing import Queue as MQueue, freeze_support #@UnresolvedImport
    1111from gi.repository import GLib
    1212
     13from xpra.server.auth.sys_auth_base import SysAuthenticator
    1314from xpra.util import (
    1415    LOGIN_TIMEOUT, AUTHENTICATION_ERROR, SESSION_NOT_FOUND, SERVER_ERROR,
    1516    repr_ellipsized, print_nested_dict, csv, envfloat, envbool, envint, typedict,
     
    9091        self.source_remove = GLib.source_remove
    9192        self._socket_timeout = PROXY_SOCKET_TIMEOUT
    9293        self._ws_timeout = PROXY_WS_TIMEOUT
     94        #sources of sessions
     95        self.source_auth = True
     96        self.source_sys = False
     97        self.source_mdns = False
     98        self.source_register = False
    9399
    94100    def init(self, opts):
    95101        log("ProxyServer.init(%s)", opts)
     
    96102        self.pings = int(opts.pings)
    97103        self.video_encoders = opts.proxy_video_encoders
    98104        self._start_sessions = opts.proxy_start_sessions
     105        self.parse_proxy_sessions(opts.proxy_sessions)
    99106        super().init(opts)
    100107        #ensure we cache the platform info before intercepting SIGCHLD
    101108        #as this will cause a fork and SIGCHLD to be emitted:
     
    103110        get_platform_info()
    104111        self.child_reaper = getChildReaper()
    105112
     113    def parse_proxy_sessions(self, proxy_sessions):
     114        if len(proxy_sessions) > 0:
     115            self.source_auth = "auth" in proxy_sessions
     116            self.source_sys = "sys" in proxy_sessions
     117            self.source_mdns = "mdns" in proxy_sessions
     118            self.source_register = "register" in proxy_sessions
     119       
     120
    106121    def init_control_commands(self):
    107122        ServerCore.init_control_commands(self)
    108123        self.control_commands["stop"] = ArgsControlCommand("stop", "stops the proxy instance on the given display",
     
    273288            log("disconnect(%s, %s)", reason, extras)
    274289            self.send_disconnect(client_proto, reason, *extras)
    275290
    276         #find the target server session:
    277291        if not client_proto.authenticators:
    278292            log.error("Error: the proxy server requires an authentication mode,")
    279293            try:
     
    283297            log.error(" use 'none' to disable authentication")
    284298            disconnect(SESSION_NOT_FOUND, "no sessions found")
    285299            return
     300       
     301       
     302       
     303       
     304       
     305       
     306        if client_proto.authenticators=="REGISTERING_KEEPALIVE":
     307            if not self.source_register:
     308                log.warn("Warning: registration not allowed")
     309                return
     310           
     311            # TODO allow keep alive if registering disabled (even after long time)? max value?
     312   
     313            # TODO sanitize input from packet (ip, token)
     314            token = "958upigpaerz"
     315            ip = "127.0.0.1"
     316   
     317            # find the target token:
     318            session = None
     319            authenticator = None
     320            for auth_authenticator in client_proto.authenticators:
     321                auth_authenticator: SysAuthenticator
     322                try:
     323                    if auth_authenticator.ALLOWS_REGISTRATION:
     324                        continue
     325           
     326                    auth_session = auth_authenticator.get_session_by_token(token)
     327                    authlog("proxy_auth %s.get_token()=%s", auth_authenticator, session)
     328                    if auth_session:
     329                        session = auth_session
     330                        authenticator = auth_authenticator
     331                        break
     332                except Exception as e:
     333                    authlog("failed to get the token from %s", auth_authenticator, exc_info=True)
     334                    authlog.error("Error: failed to get the token using '%s' authenticator", auth_authenticator)
     335                    authlog.error(" %s", e)
     336                    disconnect(AUTHENTICATION_ERROR, "cannot access token")
     337                    return
     338            authlog("proxy_auth(%s, {..}, %s) found token: %s", client_proto, auth_caps, token)
     339            if session is None:
     340                disconnect(SESSION_NOT_FOUND, "no token found")
     341                return
     342
     343            updatedSession = authenticator.update_session(session.id, ip)      # TODO refresh session in DB/Memory
     344
     345            if updatedSession is not None:
     346                answerPacket = {
     347                    "success": updatedSession is not None,
     348                    "keep_alive_time": updatedSession.keep_alive_time,
     349                }
     350                client_proto.send_now(("registration", answerPacket))
     351                return
     352            else:
     353                disconnect(SESSION_NOT_FOUND, "session not updated")
     354       
     355       
     356       
     357       
     358       
     359       
     360       
     361       
     362        elif client_proto.authenticators == "GET_NEW_TOKEN":  # one time action of registering and getting a token
     363            if not self.source_register:
     364                log.warn("Warning: registration not allowed")
     365                return
     366           
     367            # TODO sanitize input from packet
     368            user_id = "123"
     369            password = "asd"
     370            app_name = "calc"
     371            display_name = "Room 7"
     372            ip = "127.0.0.1"
     373           
     374            # find the target user:
     375            user = None
     376            authenticator = None
     377            for auth_authenticator in client_proto.authenticators:
     378                try:
     379                    if auth_authenticator.ALLOWS_REGISTRATION:
     380                        continue
     381                       
     382                    auth_user = auth_authenticator.get_user(user_id, password)
     383                    authlog("proxy_auth %s.get_user()=%s", auth_authenticator, auth_user)
     384                    if auth_user:
     385                        user = auth_user
     386                        authenticator = auth_authenticator
     387                        break
     388                except Exception as e:
     389                    authlog("failed to get the user from %s", auth_authenticator, exc_info=True)
     390                    authlog.error("Error: failed to get the user using '%s' authenticator", auth_authenticator)
     391                    authlog.error(" %s", e)
     392                    disconnect(AUTHENTICATION_ERROR, "cannot access user")
     393                    return
     394            authlog("proxy_auth(%s, {..}, %s) found user: %s", client_proto, auth_caps, user)
     395            if user is None:
     396                disconnect(SESSION_NOT_FOUND, "no user found")
     397                return
     398       
     399            new_token = generate_token()
     400       
     401            registeredSession = authenticator.create_session(user, app_name, ip, new_token, display_name) # TODO insert session into DB/Memory
     402
     403            if registeredSession is not None:
     404                answerPacket = {
     405                    "keep_alive_time": registeredSession.keep_alive_time,
     406                    "keep_alive_token": registeredSession.token
     407                }
     408                client_proto.send_now(("registration", answerPacket))
     409                return
     410            else:
     411                disconnect(SESSION_NOT_FOUND, "session not updated")
     412       
     413       
     414       
     415       
     416       
     417       
     418       
     419       
     420       
     421       
     422        else:
     423            # find the target server session:
    286424        sessions = None
    287425        for authenticator in client_proto.authenticators:
    288426            try: