Exemplo n.º 1
0
def start_term(authname, cfm, connection, params, path, authdata, skipauth):
    elems = path.split('/')
    if len(elems) < 4 or elems[1] != 'nodes':
        raise exc.InvalidArgumentException('Invalid path {0}'.format(path))
    node = elems[2]
    ccons = ClientConsole(connection)
    skipreplay = False
    if params and 'skipreplay' in params and params['skipreplay']:
        skipreplay = True
    if elems[3] == "console":
        consession = consoleserver.ConsoleSession(node=node,
                                                  configmanager=cfm,
                                                  username=authname,
                                                  datacallback=ccons.sendall,
                                                  skipreplay=skipreplay)
    elif len(elems) >= 6 and elems[3:5] == ['shell', 'sessions']:
        if len(elems) == 7:
            sessionid = elems[5]
        else:
            sessionid = None
        consession = shellserver.ShellSession(node=node,
                                              configmanager=cfm,
                                              username=authname,
                                              datacallback=ccons.sendall,
                                              skipreplay=skipreplay,
                                              sessionid=sessionid)
    else:
        raise exc.InvalidArgumentException('Invalid path {0}'.format(path))
    if consession is None:
        raise Exception("TODO")
    term_interact(authdata, authname, ccons, cfm, connection, consession,
                  skipauth)
Exemplo n.º 2
0
def start_term(authname, cfm, connection, params, path, authdata, skipauth):
    elems = path.split('/')
    if len(elems) < 4 or elems[1] != 'nodes':
        raise exc.InvalidArgumentException('Invalid path {0}'.format(path))
    node = elems[2]
    ccons = ClientConsole(connection)
    skipreplay = False
    if params and 'skipreplay' in params and params['skipreplay']:
        skipreplay = True
    if elems[3] == "console":
        consession = consoleserver.ConsoleSession(node=node,
                                                  configmanager=cfm,
                                                  username=authname,
                                                  datacallback=ccons.sendall,
                                                  skipreplay=skipreplay)
    elif len(elems) >= 6 and elems[3:5] == ['shell', 'sessions']:
        if len(elems) == 7:
            sessionid = elems[5]
        else:
            sessionid = None
        consession = shellserver.ShellSession(node=node,
                                              configmanager=cfm,
                                              username=authname,
                                              datacallback=ccons.sendall,
                                              skipreplay=skipreplay,
                                              sessionid=sessionid)

    else:
        raise exc.InvalidArgumentException('Invalid path {0}'.format(path))

    if consession is None:
        raise Exception("TODO")
    send_data(connection, {'started': 1})
    ccons.startsending()
    bufferage = consession.get_buffer_age()
    if bufferage is not False:
        send_data(connection, {'bufferage': bufferage})
    while consession is not None:
        data = tlvdata.recv(connection)
        if type(data) == dict:
            if data['operation'] == 'stop':
                consession.destroy()
                return
            elif data['operation'] == 'break':
                consession.send_break()
                continue
            elif data['operation'] == 'reopen':
                consession.reopen()
                continue
            else:
                process_request(connection, data, cfm, authdata, authname,
                                skipauth)
                continue
        if not data:
            consession.destroy()
            return
        consession.write(data)
Exemplo n.º 3
0
def start_proxy_term(connection, cert, request):
    cert = crypto.dump_certificate(crypto.FILETYPE_ASN1, cert)
    droneinfo = configmanager.get_collective_member(request['name'])
    if not util.cert_matches(droneinfo['fingerprint'], cert):
        connection.close()
        return
    cfm = configmanager.ConfigManager(request['tenant'])
    ccons = ClientConsole(connection)
    consession = consoleserver.ConsoleSession(node=request['node'],
                                              configmanager=cfm,
                                              username=request['user'],
                                              datacallback=ccons.sendall,
                                              skipreplay=request['skipreplay'])
    term_interact(None, None, ccons, None, connection, consession, None)
Exemplo n.º 4
0
def resourcehandler_backend(env, start_response):
    """Function to handle new wsgi requests
    """
    mimetype, extension = _pick_mimetype(env)
    headers = [('Content-Type', mimetype), ('Cache-Control', 'no-store'),
               ('Pragma', 'no-cache'), ('X-Content-Type-Options', 'nosniff'),
               ('Content-Security-Policy', "default-src 'self'"),
               ('X-XSS-Protection', '1; mode=block'),
               ('X-Frame-Options', 'deny'),
               ('Strict-Transport-Security', 'max-age=86400'),
               ('X-Permitted-Cross-Domain-Policies', 'none')]
    reqbody = None
    reqtype = None
    if 'CONTENT_LENGTH' in env and int(env['CONTENT_LENGTH']) > 0:
        reqbody = env['wsgi.input'].read(int(env['CONTENT_LENGTH']))
        reqtype = env['CONTENT_TYPE']
    operation = opmap[env['REQUEST_METHOD']]
    querydict = _get_query_dict(env, reqbody, reqtype)
    if 'restexplorerop' in querydict:
        operation = querydict['restexplorerop']
        del querydict['restexplorerop']
    authorized = _authorize_request(env, operation)
    if 'logout' in authorized:
        start_response('200 Successful logout', headers)
        yield ('{"result": "200 - Successful logout"}')
        return
    if 'HTTP_SUPPRESSAUTHHEADER' in env or 'HTTP_CONFLUENTAUTHTOKEN' in env:
        badauth = [('Content-type', 'text/plain')]
    else:
        badauth = [('Content-type', 'text/plain'),
                   ('WWW-Authenticate', 'Basic realm="confluent"')]
    if authorized['code'] == 401:
        start_response('401 Authentication Required', badauth)
        yield 'authentication required'
        return
    if authorized['code'] == 403:
        start_response('403 Forbidden', badauth)
        yield 'authorization failed'
        return
    if authorized['code'] != 200:
        raise Exception("Unrecognized code from auth engine")
    headers.extend(("Set-Cookie", m.OutputString())
                   for m in authorized['cookie'].values())
    cfgmgr = authorized['cfgmgr']
    if (operation
            == 'create') and env['PATH_INFO'] == '/sessions/current/async':
        pagecontent = ""
        try:
            for rsp in _assemble_json(
                    confluent.asynchttp.handle_async(
                        env, querydict,
                        httpsessions[authorized['sessionid']]['inflight'])):
                pagecontent += rsp
            start_response("200 OK", headers)
            yield pagecontent
            return
        except exc.ConfluentException as e:
            if e.apierrorcode == 500:
                # raise generics to trigger the tracelog
                raise
            start_response('{0} {1}'.format(e.apierrorcode, e.apierrorstr),
                           headers)
            yield e.get_error_body()
    elif (env['PATH_INFO'].endswith('/forward/web')
          and env['PATH_INFO'].startswith('/nodes/')):
        prefix, _, _ = env['PATH_INFO'].partition('/forward/web')
        _, _, nodename = prefix.rpartition('/')
        hm = cfgmgr.get_node_attributes(nodename, 'hardwaremanagement.manager')
        targip = hm.get(nodename, {}).get('hardwaremanagement.manager',
                                          {}).get('value', None)
        if not targip:
            start_response('404 Not Found', headers)
            yield 'No hardwaremanagemnet.manager defined for node'
            return
        funport = forwarder.get_port(targip, env['HTTP_X_FORWARDED_FOR'],
                                     authorized['sessionid'])
        host = env['HTTP_X_FORWARDED_HOST']
        url = 'https://{0}:{1}/'.format(host, funport)
        start_response('302', [('Location', url)])
        yield 'Our princess is in another castle!'
        return
    elif (operation == 'create'
          and ('/console/session' in env['PATH_INFO']
               or '/shell/sessions/' in env['PATH_INFO'])):
        #hard bake JSON into this path, do not support other incarnations
        if '/console/session' in env['PATH_INFO']:
            prefix, _, _ = env['PATH_INFO'].partition('/console/session')
            shellsession = False
        elif '/shell/sessions/' in env['PATH_INFO']:
            prefix, _, _ = env['PATH_INFO'].partition('/shell/sessions')
            shellsession = True
        _, _, nodename = prefix.rpartition('/')
        if 'session' not in querydict.keys() or not querydict['session']:
            auditmsg = {
                'operation': 'start',
                'target': env['PATH_INFO'],
                'user': authorized['username'],
            }
            if 'tenant' in authorized:
                auditmsg['tenant'] = authorized['tenant']
            auditlog.log(auditmsg)
            # Request for new session
            skipreplay = False
            if 'skipreplay' in querydict and querydict['skipreplay']:
                skipreplay = True
            datacallback = None
            async = None
            if 'HTTP_CONFLUENTASYNCID' in env:
                async = confluent.asynchttp.get_async(env, querydict)
                termrel = async .set_term_relation(env)
                datacallback = termrel.got_data
            try:
                if shellsession:
                    consession = shellserver.ShellSession(
                        node=nodename,
                        configmanager=cfgmgr,
                        username=authorized['username'],
                        skipreplay=skipreplay,
                        datacallback=datacallback)
                else:
                    consession = consoleserver.ConsoleSession(
                        node=nodename,
                        configmanager=cfgmgr,
                        username=authorized['username'],
                        skipreplay=skipreplay,
                        datacallback=datacallback)
            except exc.NotFoundException:
                start_response("404 Not found", headers)
                yield "404 - Request Path not recognized"
                return
            if not consession:
                start_response("500 Internal Server Error", headers)
                return
            sessid = _assign_consessionid(consession)
            if async:
                async .add_console_session(sessid)
            start_response('200 OK', headers)
            yield '{"session":"%s","data":""}' % sessid
            return
        elif 'bytes' in querydict.keys():  # not keycodes...
            myinput = querydict['bytes']
            sessid = querydict['session']
            if sessid not in consolesessions:
                start_response('400 Expired Session', headers)
                return
            consolesessions[sessid]['expiry'] = time.time() + 90
            consolesessions[sessid]['session'].write(myinput)
            start_response('200 OK', headers)
            yield json.dumps({'session': querydict['session']})
            return  # client has requests to send or receive, not both...
        elif 'closesession' in querydict:
            consolesessions[querydict['session']]['session'].destroy()
            del consolesessions[querydict['session']]
            start_response('200 OK', headers)
            yield '{"sessionclosed": true}'
            return
        elif 'action' in querydict:
            if querydict['action'] == 'break':
                consolesessions[querydict['session']]['session'].send_break()
            elif querydict['action'] == 'reopen':
                consolesessions[querydict['session']]['session'].reopen()
            else:
                start_response('400 Bad Request')
                yield 'Unrecognized action ' + querydict['action']
                return
            start_response('200 OK', headers)
            yield json.dumps({'session': querydict['session']})
        else:  # no keys, but a session, means it's hooking to receive data
            sessid = querydict['session']
            if sessid not in consolesessions:
                start_response('400 Expired Session', headers)
                yield ''
                return
            consolesessions[sessid]['expiry'] = time.time() + 90
            # add our thread to the 'inflight' to have a hook to terminate
            # a long polling request
            loggedout = None
            mythreadid = greenlet.getcurrent()
            httpsessions[authorized['sessionid']]['inflight'].add(mythreadid)
            try:
                outdata = consolesessions[sessid]['session'].get_next_output(
                    timeout=25)
            except greenlet.GreenletExit as ge:
                loggedout = ge
            httpsessions[authorized['sessionid']]['inflight'].discard(
                mythreadid)
            if sessid not in consolesessions:
                start_response('400 Expired Session', headers)
                yield ''
                return
            if loggedout is not None:
                consolesessions[sessid]['session'].destroy()
                start_response('401 Logged out', headers)
                yield '{"loggedout": 1}'
                return
            bufferage = False
            if 'stampsent' not in consolesessions[sessid]:
                consolesessions[sessid]['stampsent'] = True
                bufferage = consolesessions[sessid]['session'].get_buffer_age()
            if isinstance(outdata, dict):
                rspdata = outdata
                rspdata['session'] = querydict['session']
            else:
                rspdata = {'session': querydict['session'], 'data': outdata}
            if bufferage is not False:
                rspdata['bufferage'] = bufferage
            try:
                rsp = json.dumps(rspdata)
            except UnicodeDecodeError:
                try:
                    rsp = json.dumps(rspdata, encoding='cp437')
                except UnicodeDecodeError:
                    rsp = json.dumps({
                        'session': querydict['session'],
                        'data': 'DECODEERROR'
                    })
            start_response('200 OK', headers)
            yield rsp
            return
    else:
        # normal request
        url = env['PATH_INFO']
        url = url.replace('.json', '')
        url = url.replace('.html', '')
        if url == '/sessions/current/info':
            start_response('200 OK', headers)
            sessinfo = {'username': authorized['username']}
            if 'authtoken' in authorized:
                sessinfo['authtoken'] = authorized['authtoken']
            yield json.dumps(sessinfo)
            return
        resource = '.' + url[url.rindex('/'):]
        lquerydict = copy.deepcopy(querydict)
        try:
            hdlr = pluginapi.handle_path(url, operation, cfgmgr, querydict)
            if 'HTTP_CONFLUENTASYNCID' in env:
                confluent.asynchttp.run_handler(hdlr, env)
                start_response('202 Accepted', headers)
                yield 'Request queued'
                return
            pagecontent = ""
            if mimetype == 'text/html':
                for datum in _assemble_html(hdlr, resource, lquerydict, url,
                                            extension):
                    pagecontent += datum
            else:
                for datum in _assemble_json(hdlr, resource, url, extension):
                    pagecontent += datum
            start_response('200 OK', headers)
            yield pagecontent
        except exc.ConfluentException as e:
            if ((not isinstance(e, exc.LockedCredentials))
                    and e.apierrorcode == 500):
                # raise generics to trigger the tracelog
                raise
            start_response('{0} {1}'.format(e.apierrorcode, e.apierrorstr),
                           headers)
            yield e.get_error_body()
Exemplo n.º 5
0
def wsock_handler(ws):
    sessid = ws.wait()
    sessid = sessid.replace('ConfluentSessionId:', '')
    sessid = sessid[:-1]
    currsess = httpsessions.get(sessid, None)
    if not currsess:
        return
    authtoken = ws.wait()
    authtoken = authtoken.replace('ConfluentAuthToken:', '')
    authtoken = authtoken[:-1]
    if currsess['csrftoken'] != authtoken:
        return
    mythreadid = greenlet.getcurrent()
    httpsessions[sessid]['inflight'].add(mythreadid)
    name = httpsessions[sessid]['name']
    authdata = auth.authorize(name, ws.path)
    if not authdata:
        return
    if '/console/session' in ws.path or '/shell/sessions/' in ws.path:
        #hard bake JSON into this path, do not support other incarnations
        if '/console/session' in ws.path:
            prefix, _, _ = ws.path.partition('/console/session')
            shellsession = False
        elif '/shell/sessions/' in ws.path:
            prefix, _, _ = ws.path.partition('/shell/sessions')
            shellsession = True
        _, _, nodename = prefix.rpartition('/')
        geom = ws.wait()
        geom = geom[1:]
        geom = json.loads(geom)
        width = geom['width']
        height = geom['height']
        skipreplay = geom.get('skipreplay', False)
        cfgmgr = httpsessions[sessid]['cfgmgr']
        username = httpsessions[sessid]['name']

        def datacallback(data):
            if isinstance(data, dict):
                data = json.dumps(data)
                ws.send(u'!' + data)
            else:
                try:
                    data = data.decode('utf8')
                except UnicodeDecodeError:
                    data = data.decode('cp437')
                ws.send(u' ' + data)

        try:
            if shellsession:
                consession = shellserver.ShellSession(
                    node=nodename,
                    configmanager=cfgmgr,
                    username=username,
                    skipreplay=skipreplay,
                    datacallback=datacallback,
                    width=width,
                    height=height)
            else:
                consession = consoleserver.ConsoleSession(
                    node=nodename,
                    configmanager=cfgmgr,
                    username=username,
                    skipreplay=skipreplay,
                    datacallback=datacallback,
                    width=width,
                    height=height)
        except exc.NotFoundException:
            return
        clientmsg = ws.wait()
        try:
            while clientmsg is not None:
                if clientmsg[0] == ' ':
                    consession.write(clientmsg[1:])
                elif clientmsg[0] == '!':
                    cmd = json.loads(clientmsg[1:])
                    action = cmd.get('action', None)
                    if action == 'break':
                        consession.send_break()
                    elif action == 'resize':
                        consession.resize(width=cmd['width'],
                                          height=cmd['height'])
                elif clientmsg[0] == '?':
                    ws.send(u'?')
                clientmsg = ws.wait()
        finally:
            consession.destroy()